【发布时间】:2016-02-20 01:02:22
【问题描述】:
我需要与其中一台邮件服务器进行交换,使用 RFC3030 接收大型 mime 消息。 原始任务是:如果 MIME 消息大小 > 80MB,我需要使用 RFC3030。
我怎么理解,JavaMail 不能“从盒子里”做到这一点?
也许我可以为实现 RFC3030 的 JavaMail 创建一些处理程序或扩展?
请帮忙。我不知道该怎么办。
【问题讨论】:
标签: java jakarta-mail
我需要与其中一台邮件服务器进行交换,使用 RFC3030 接收大型 mime 消息。 原始任务是:如果 MIME 消息大小 > 80MB,我需要使用 RFC3030。
我怎么理解,JavaMail 不能“从盒子里”做到这一点?
也许我可以为实现 RFC3030 的 JavaMail 创建一些处理程序或扩展?
请帮忙。我不知道该怎么办。
【问题讨论】:
标签: java jakarta-mail
快速查看SMTPTransport 确认:普通的旧 JavaMail 不支持 BDAT,它总是会尝试使用 DATA 命令发送,如下所示:
this.message.writeTo(data(), ignoreList);
finishData();
如果您不害怕(并且没有法律理由不)修改核心 JDK 类,您可以覆盖方法 data() 和 finishData() 因为它们都受到保护(源代码来自here ):
/**
* Send the <code>DATA</code> command to the SMTP host and return
* an OutputStream to which the data is to be written.
*
* @since JavaMail 1.4.1
*/
protected OutputStream data() throws MessagingException {
assert Thread.holdsLock(this);
issueSendCommand("DATA", 354);
dataStream = new SMTPOutputStream(serverOutput);
return dataStream;
}
/**
* Terminate the sent data.
*
* @since JavaMail 1.4.1
*/
protected void finishData() throws IOException, MessagingException {
assert Thread.holdsLock(this);
dataStream.ensureAtBOL();
issueSendCommand(".", 250);
}
为了支持RFC3030,我建议您首先将整个消息缓冲到ByteArrayOutputStream 中,您需要确定要发送的消息的大小。如果“小”-> 像SMTPTransport 那样做就可以了。如果“大”,则将字节分成块并以BDAT 样式发送。我建议以 0 lentgh LAST BDAT 和代码结尾
protected void finishData() throws IOException, MessagingException {
assert Thread.holdsLock(this);
dataStream.ensureAtBOL();
issueSendCommand("BDAT 0 LAST", 250);
}
-- 编辑--
这是一个非常简单的第一种方法,还有很多事情需要做得更好。最重要的是,outputStream 发送数据块,而message.writeTo() 不断填充数据块的即用即用实现。填充一个大字节 [] 只是为了稍后将其分成块,这在内存占用方面非常非常糟糕。但是这样更容易阅读,因为所有的分块和发送都发生在一个地方。请注意,此示例使用反射来访问 Oracle 的 SMTPTransport 中的 serverOutput 字段。因此,任何新版本的 JavaMail 都可能在没有任何警告的情况下随时中断。此外,我的异常处理暂时不遵循 RFC-3030,因为如果 BDAT 失败,则不会执行 RSET。
package de.janschweizer;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.lang.reflect.Field;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.URLName;
import com.sun.mail.smtp.SMTPOutputStream;
public class SMTPTransport extends com.sun.mail.smtp.SMTPTransport {
//We can have our own copy - it's only used in the methods we override anyways.
private SMTPOutputStream dataStream;
private ByteArrayOutputStream baos;
public SMTPTransport(Session session, URLName urlname, String string, boolean bool) {
super(session, urlname, string, bool);
}
public SMTPTransport(Session session, URLName urlname) {
super(session, urlname);
}
protected OutputStream data() throws MessagingException {
assert(Thread.holdsLock(this));
if(!supportsExtension("CHUNKING")) {
return super.data();
}
baos = new ByteArrayOutputStream();
this.dataStream = new SMTPOutputStream(baos);
return this.dataStream;
}
protected void finishData() throws IOException, MessagingException {
assert(Thread.holdsLock(this));
if(!supportsExtension("CHUNKING")) {
super.finishData();
return;
}
this.dataStream.ensureAtBOL();
dataStream.flush();
BufferedReader br = new BufferedReader(new StringReader(new String(baos.toByteArray())));
try {
//BAD reflection hack
Field fServerOutput = com.sun.mail.smtp.SMTPTransport.class.getDeclaredField("serverOutput");
fServerOutput.setAccessible(true);
OutputStream os = (OutputStream)fServerOutput.get(this);
//Do the Chunky
ByteArrayOutputStream bchunk = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(bchunk);
String line = br.readLine();
int linecount = 0;
while(line != null) {
pw.println(line);
if(++linecount % 5000 == 0) {
pw.flush();
byte[] chunk = bchunk.toByteArray();
sendChunk(os, chunk);
bchunk = new ByteArrayOutputStream();
pw = new PrintWriter(bchunk);
}
line = br.readLine();
}
pw.flush();
byte[] chunk = bchunk.toByteArray();
sendLastChunk(os, chunk);
} catch (Exception e) {
throw new MessagingException("ReflectionError", e);
}
}
private void sendChunk(OutputStream os, byte[] chunk) throws MessagingException, IOException {
sendCommand("BDAT "+chunk.length);
os.write(chunk);
os.flush();
int rc = readServerResponse();
if(rc != 250) {
throw new MessagingException("Something very wrong");
}
}
private void sendLastChunk(OutputStream os, byte[] chunk) throws MessagingException, IOException {
sendCommand("BDAT "+chunk.length+" LAST");
os.write(chunk);
os.flush();
int rc = readServerResponse();
if(rc != 250) {
throw new MessagingException("Something very wrong");
}
}
}
有了这个 META-INF/javamail.providers
protocol=smtp; type=transport; class=de.janschweizer.SMTPTransport; vendor=Jan Schweizer;
【讨论】: