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

时间:2015-11-30 22:58:51

标签: java javamail 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不依赖于"现有" InputStream然后就可以了。但是如果我返回一个“现有的”InputStream,那么电子邮件消息将以零字节附件的形式发送。

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

5 个答案:

答案 0 :(得分:2)

我重写了您的InputStreamDataSource类,它对我有用。

tomcat-embed-jasper

}

答案 1 :(得分:1)

如果InputStream包含mime标头,则使用javax.mail.internet.MimeBodyPart(InputStream)构造函数。您不需要使用自定义DataSource课程。

否则,如果InputStream只是没有标题的正文,则将流转换为字节数组,并使用javax.mail.internet.MimeBodyPart(InternetHeaders, byte[])构造函数提供标题。

答案 2 :(得分:1)

我解决了将InputStream转换为字节数组并将其转换为Base64格式的问题。

//get file name
String fileName = ...;
//get content type
String fileContentType = ...;
//get file content
InputStream fileStream = ...;

//convert to byte array
byte[] fileByteArray = IOUtils.toByteArray(fileStream);
//and convert to Base64
byte[] fileBase64ByteArray = java.util.Base64.getEncoder().encode(fileByteArray);

//manually define headers
InternetHeaders fileHeaders = new InternetHeaders();
fileHeaders.setHeader("Content-Type", fileContentType + "; name=\"" + fileName + "\"");
fileHeaders.setHeader("Content-Transfer-Encoding", "base64");
fileHeaders.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

//build MIME body part
MimeBodyPart mbp = new MimeBodyPart(fileHeaders, fileBase64ByteArray);
mbp.setFileName(fileName);

//add it to the multipart
multipart.addBodyPart(mbp);

答案 3 :(得分:0)

编辑:

请参阅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邮件实现在输入流上进行了两次:

  1. 首先确定是否应设置标题" Content-Transfer-Encoding"到7或8位(见Content Transfer Encoding 7bit or 8 bit
  2. 然后第二次实际写入消息
  3. ...哪种糟糕,因为整个流(可能通过慢速连接可能有数百MB)将被读取两次......并且导致了对于& #34;消耗"一旦阅读。

    第一个"解决方法"我试过自己指定标题:

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

    ...按此顺序,而不是反过来...因为某些原因setDataHandler在内部调用另一个方法invalidateContentHeaders,它再次清除"Content-Transfer-Encoding"标题(wtf) ?!)

    听起来不错,邮件已发送,万岁! :D ...... :(见下一页

    附件发送...但已损坏

    我的邮件服务器中收到的文件已损坏。呵呵。 为什么?!的。经过长时间的搜索并再次钻研这个糟糕的java邮件代码后,我发现它,它们将InputStream传输到LineOutputStream,它会更改二进制数据的行结尾。咩。 java邮件实现真的很乱。 :/

答案 4 :(得分:0)

我使用此代码发送带有网络下载附件的电子邮件。您可以轻松编辑它以达到您的目的。在mimeType中使用附件的mime类型。快乐的编码。

this.Bind<IQueryServiceFactory>()
    .ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());