我需要與其中一個郵件服務器進行交換,使用RFC3030作爲大型MIME郵件。 原始任務是:如果MIME消息大小> 80MB,則需要使用RFC3030。大郵件和二進制MIME郵件的JavaMail傳輸(rfc3030)
我怎麼理解,JavaMail不能做到「從盒子裏」?
也許我可以爲實現RFC3030的JavaMail創建一些處理程序或擴展?
請幫忙。我不知道該怎麼辦。
我需要與其中一個郵件服務器進行交換,使用RFC3030作爲大型MIME郵件。 原始任務是:如果MIME消息大小> 80MB,則需要使用RFC3030。大郵件和二進制MIME郵件的JavaMail傳輸(rfc3030)
我怎麼理解,JavaMail不能做到「從盒子裏」?
也許我可以爲實現RFC3030的JavaMail創建一些處理程序或擴展?
請幫忙。我不知道該怎麼辦。
快速查看SMTPTransport
證實:普通老式的JavaMail不支持BDAT,它總是會嘗試使用DATA命令發送這樣的:
this.message.writeTo(data(), ignoreList);
finishData();
如果你不害怕(,沒有任何法律理由不)與核心JDK類鼓搗,你可以覆蓋的方法數據()和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,我d建議你從開始將整個消息緩存到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;
是的,這可能是正確的做法,但代碼應該檢查服務器是否支持做任何的在此之前的CHUNKING擴展。此外,您應該能夠繼承SMTPTransport,創建自己的Transport類型,並使用javamail.providers文件將其打包到自己的jar文件中,並且可以與JavaMail一起使用,而不必更改JavaMail本身。 –
@BillShannon是的,創建自己的實現和子類化聽起來不錯。太糟糕了,所有的dataStream,serverOutput和issueSendCommand都是私有的。沒有完整的源代碼副本或真正糟糕的反思黑客,這是一個死衚衕。 – Jan
@BillShannon刮痕。反正我們只需要serverOutput。以受保護的方式訪問該文件可能會更好 – Jan