【问题标题】:JavaMail InputStream attachment takes foreverJavaMail InputStream 附件需要永远
【发布时间】:2014-02-02 22:16:07
【问题描述】:

我正在尝试发送带有附件的电子邮件。附件是即时生成的,因此没有文件,我无法在文件系统上创建临时文件。

InputStream attachment

我尝试过直接使用 JavaMail 和 apache.commons.mail。两者我都有相同的结果。浏览器停留为“等待本地主机”需要 6 分钟。我怀疑问题是邮件库并不真正知道 InputStream 有多大(或者他们没有正确处理 InputStream),所以他们等到某个超时然后发送邮件。我已经对文件进行了测试(通过 FileDataSource 和其他),它工作正常,但不是 InputStream...

有什么方法可以让它工作而不会让用户永远等待吗?当然减少 timeOut 不是一个好的解决方案,因为我不知道连接的速度和速度有多快另一方面,我不想让快速用户等待发送 200KB 的电子邮件。

 // Create the email message
    MultiPartEmail email2 = new MultiPartEmail();
    email2.setHostName(host);
    email2.setAuthenticator(new DefaultAuthenticator(username, password));
    email2.setSSLOnConnect(true);
    email2.setFrom(username);
    email2.setSmtpPort( Integer.parseInt(port) );
    email2.addTo(to);
    email2.setSubject("MAIL");
    email2.setMsg("Text");

    DataSource source = new ByteArrayDataSource(attachment, "application/pdf");  
    // add the attachment
    email2.attach(source, "somefile.pdf", "Description of some file");
    email2.send();

此代码将正确发送邮件...但在 6 分钟或更长时间后。

编辑

我在代码中放置了一些痕迹:

DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
System.out.println("Start: " + dateFormat.format(date));
 // Create the email message
    MultiPartEmail email2 = new MultiPartEmail();
    email2.setHostName(host);
    email2.setAuthenticator(new DefaultAuthenticator(username, password));
    email2.setSSLOnConnect(true);
    email2.setFrom(username);
    email2.setSmtpPort( Integer.parseInt(port) );
    email2.addTo(emailTO);
    email2.setSubject("MAIL");
    email2.setMsg("Text");
date = new Date();
System.out.println("Before DataSource: " + dateFormat.format(date));
    DataSource source = new ByteArrayDataSource(attachment, "application/pdf");  
date = new Date();
System.out.println("After DataSource: " + dateFormat.format(date));
    // add the attachment
    email2.attach(source, "somefile.pdf", "Description of some file");
date = new Date();
System.out.println("Before send(): " + dateFormat.format(date));
    email2.send();
date = new Date();
System.out.println("After send(): " + dateFormat.format(date));

结果是这样的:

Start: 2014/02/24 16:18:01
Before DataSource: 2014/02/24 16:18:01
After DataSource: 2014/02/24 16:18:01
Before send(): 2014/02/24 16:18:01
Feb 24, 2014 4:18:01 PM org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage getColorSpace
INFO: About to return NULL from unhandled branch. filter = COSName{DCTDecode}
After send(): 2014/02/24 16:26:35

如果我评论 email2.attach(...) 我会得到:

Start: 2014/02/24 16:28:56
Before DataSource: 2014/02/24 16:28:56
After DataSource: 2014/02/24 16:28:56
Before send(): 2014/02/24 16:28:56
After send(): 2014/02/24 16:29:27

当然需要很长的时间,但这是可以接受的......

现在,很明显问题与附件有关。不过,我不确定收到 PDFBox 警告是什么...

编辑 2

我现在正在测试没有附件,发送电子邮件只需要 5 秒...所以它看起来确实与访问 InputStream 的方式有关。

编辑 3

我启用了调试,似乎附件中消耗了时间。我看到 send() 做了什么并打印了:

------=_Part_0_2141791733.1395266799862
Content-Type: application/pdf; name="my.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="my.pdf"
Content-Description: 

JVBERi0xLjQKJfbk/N8KMSAwIG9iago8PAovTWFya0luZm8gMiAwIFIKL01ldGFkYXRhIDMgMCBS

... 然后 send() 将附件内容一点一点地打印出来,如下所示:

MhKxjVRnwA6I8BisAX1VTXc0hw1DXO0lBcQJDQpWFZPU3oX2YogU3Y0SbgFxKBCJWzUEqfJIQ5Bh
GrYDx1o3JOIYHZPnVRZHa4EA0FqGxiZk6MdkEfYakPO4MW1jXIjeKFMxdL1XY84nrGDMwoyCkC3N
TJOAJITplbIewNEXv6u8AIf64hiZIm+x4jyFOxzk5DzfSONJiDiKbtozF+Yz+g90lJOCLiRFneuV
3AYDQAD1gnW+odwoSVBAUezLL5Zwue1yttDySw5zVsaE9j7kv9mHpOlnTephlZR5fiu/f+XEOb/O
qQ6suP2zOl/3KRw+OMiXC5hNGlAca7d2XWDMLIiQs45yUsCnljRLVdYFKz7Zg6zcsiH9kaupwOe4
ifPEiXe/8LEok2So8o3Bp5XysDadYxsllfVLlNdLXlQc+2R+kdFHam5ydBm5HkYl5ZCwF2vPKpvU

然后它需要几秒钟......并打印另一个块。这个过程持续大约 6 分钟。直到完成:

MjRDODdCODVGMEEyQjBBMzVDQj4gPEM5MjBBRjU5Q0MxOEM2NDI5MDM4REIzMEI2OUE0REQ5Pl0K
L1Jvb3QgMSAwIFIKL0luZm8gNyAwIFIKL1hSZWZTdG0gMTYxOAo+PgpzdGFydHhyZWYKNDEzNjI5
CiUlRU9GCg==
------=_Part_0_690515382.1395264718480--
.
250 OK id=4WQO3h-0004D1-VQ
QUIT
221 mail2.... closing connection

我猜InputStream 有问题。没有附件或从文件中获取附件,它工作得很好而且很快。附件只有 ~0.4MB

也许InputStream 的创建方式有些问题。但这似乎很奇怪,因为我使用完全相同的方法下载 PDF,并且下载效果很好。

    ByteArrayOutputStream os = new ByteArrayOutputStream();
    pd.save(os);
    return new ByteArrayInputStream( os.toByteArray() );

【问题讨论】:

  • InputStream 是从哪里来的?你真的确定时间花在了 send() 中吗?而不是例如构造 ByteArrayDataSource?
  • 我放了一些日志,时间花在了send()中。 INpuTStream 来自另一个动态生成 PDF 的函数(也是我创建的)。

标签: java jakarta-mail inputstream attachment


【解决方案1】:

到底哪个语句一直在占用?它是在创建 ByteArrayDataSource 吗?还是发送方法? ByteArrayDataSource 将所有数据立即复制到一个字节数组中。如果那是一直存在的地方,那么您自己也许可以更有效地做到这一点。但如果所有时间都在 send 方法中,则可能是您的邮件服务器速度较慢。

【讨论】:

  • 我放了一些日志,时间花在了send()中。它不太可能是一个慢速服务器,因为我尝试使用同一服务器从文件系统发送文件并且它很快(无论如何通过 InputStream 发送一个小文件需要很长时间)。
  • 在发送完成时 InputStream 早已不复存在。正如我所说,ByteArrayDataSource 会立即复制所有数据。尝试使用 FileInputStream 并且发送应该与您的 InputStream 具有相同的性能。如果您使用 FileDataSource 并在相同数量的数据下看到更好的性能,我们需要更多关于您如何测量性能以及如何重现问题的详细信息。尝试针对(例如)Gmail 进行测试,以确保它与您的服务器无关。
  • 您是否尝试使用 FileInputStream 来查看性能有何不同?我不知道您是否可以使用您正在使用的包装类来做到这一点,但不要发送消息,而是使用 MimeMessage.writeTo 方法将其写入文件以查看其性能。打开 JavaMail Session 调试并观察输出。如果发送消息需要 6 分钟,您也许可以看到发送过程中的哪个位置暂停了很长时间。
  • 如果将消息写入文件而不是发送,需要多长时间?您是否安装了防病毒或防火墙程序?如果禁用它,性能会改变吗?如果您只是自己阅读 InputStream,需要多长时间?只是为了确认,如您上面的代码,“附件”是您的 InputStream 并且您使用的是 ByteArrayDataSource,对吗?
猜你喜欢
  • 2011-08-12
  • 2013-12-08
  • 2021-03-17
  • 2014-02-24
  • 2014-07-08
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多