java - 使用现有 InputStream 作为附件内容使用 javax.mail 发送电子邮件

标签 java jakarta-mail javax.activation

是否可以使用 javax.mail 发送电子邮件并使用“现有”InputStream 作为电子邮件附件内容?

目前我正在构建如下电子邮件消息:

final MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject("Subject line");

final Multipart multipartContent = new MimeMultipart();

    final MimeBodyPart textPart = new MimeBodyPart();
    textPart.setText("Message body");
    multipartContent.addBodyPart(textPart);

    final MimeBodyPart attachmentPart = new MimeBodyPart();
    final DataSource source = new InputStreamDataSource("text/plain", "test.txt", new ByteArrayInputStream("CONTENT INPUT STREAM".getBytes()));
    attachmentPart.setDataHandler(new DataHandler(source));
    attachmentPart.setFileName("text.txt");
    multipartContent.addBodyPart(attachmentPart);

message.setContent(multipartContent);

InputStreamDataSource实现如下:

public class InputStreamDataSource implements DataSource
{
    private final String contentType;
    private final String name;
    private final InputStream inputStream;

    public InputStreamDataSource(String contentType, String name, InputStream inputStream)
    {
        this.contentType = contentType;
        this.name = name;
        this.inputStream = inputStream;
    }

    public String getContentType()
    {
        return contentType;
    }

    public String getName()
    {
        return name;
    }

    public InputStream getInputStream() throws IOException
    {
        System.out.println("CALLED TWICE: InputStreamDataSource.getInputStream()");
        return new BufferedInputStream(inputStream);
        //return new ByteArrayInputStream("THIS 'NEW' INPUT STREAM WORKS BUT 'EXISTING' INPUT STREAM RESULTS IN ZERO-BYTE ATTACHMENT".getBytes());
    }

    public OutputStream getOutputStream() throws IOException
    {
        throw new UnsupportedOperationException("Not implemented");
    }
}

DataSource 提供方法getInputStream() 来获取电子邮件附件内容的InputStream

如果我返回一个不依赖于“现有”InputStream 的"new"InputStream,那么它可以正常工作。但是,如果我返回一个“现有的”InputStream,那么电子邮件将以一个零字节的附件发送。

是否可以使用 javax.mail 发送电子邮件,并使用“现有”InputStream 作为电子邮件附件内容?

最佳答案

编辑:

参见 https://community.oracle.com/thread/1590625

TL;DR 使用ByteArrayDataSource


必须深入研究 Oracle 的源代码... https://java.net/projects/javamail/sources/mercurial/content/mail/src/main/java/javax/mail/internet/MimeBodyPart.java

当前的 java 邮件实现在输入流上运行了 2 次:

  1. 首先确定是否应该将 header “Content-Transfer-Encoding”设置为 7 位或 8 位(参见 Content Transfer Encoding 7bit or 8 bit)
  2. 然后在它实际写入消息时第二次

...这有点糟透了,因为整个流(在慢速连接上可能有数百 MB)将被读取两次...并且对于“消费”一次阅读。


我尝试的第一个“解决方法”是自己指定 header :

attachmentPart.setDataHandler(new DataHandler(source));
attachmentPart.setHeader("Content-Transfer-Encoding", "8bit");
attachmentPart.setHeader("Content-Type", ds.getContentType() + "; " + ds.getName());

...并按此顺序,而不是相反...因为某些原因 setDataHandler 在内部调用另一个方法 invalidateContentHeaders 清除 “Content-Transfer-Encoding” 再次 header (wtf?!)

听起来很棒,邮件已发送,万岁!!! :D ... :( 看下一个


附件已发送...但已损坏

我的邮件服务器中收到的文件已损坏。嗯。 为什么?!。经过长时间的搜索并再次深入研究这个蹩脚的 java 邮件代码,我找到了,他们将 InputStream 通过管道传输到 LineOutputStream 中,这会更改 二进制文件的行尾 数据。嗯。 java邮件实现真是一团糟。 :/

关于java - 使用现有 InputStream 作为附件内容使用 javax.mail 发送电子邮件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34009587/

相关文章:

java - 为什么我的 Java 代码不执行 System.out.println?

java - 客户端似乎已连接但服务器未接受它

java - java中的HashMap函数keyset()

java - 线程中出现异常 "main"java.lang.RuntimeException : javax. mail.MessagingException : Could not connect to SMTP host: smtp. gmail.com,端口:578;

java - 使用 mail-service.xml 文件从 jboss 发送电子邮件

java - 如何在Java中使用drawString()绘制任何文本

Java - 如何验证用户名和密码

Java Mail API - 来自 FileInputStream 的数据源

java - 控制用于 MimeMessage 附件的 DataContentHandler?