是否可以使用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
作为电子邮件附件内容?
答案 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邮件实现在输入流上进行了两次:
...哪种糟糕,因为整个流(可能通过慢速连接可能有数百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());