阅读更多
2. 分析Spring mail的内部源码
我们写的DummySpringMail类中的sendMsg()方法,将实际要发送的消息通过MailSender的send方法发送了。我们看一下send方法内部的实现:
public void send(SimpleMailMessage simpleMessage) throws MailException {
send(new SimpleMailMessage[] { simpleMessage });
}
public void send(SimpleMailMessage[] simpleMessages) throws MailException {
List mimeMessages = new ArrayList(simpleMessages.length);
for (SimpleMailMessage simpleMessage : simpleMessages) {
MimeMailMessage message = new MimeMailMessage(createMimeMessage());
simpleMessage.copyTo(message);
mimeMessages.add(message.getMimeMessage());
}
doSend(mimeMessages.toArray(new MimeMessage[mimeMessages.size()]), simpleMessages);
}
我们可以看到,这里将发送的SimpleMailMessage消息转化为了javax.mail.internet.MimeMessage,这正是我们前文提到的。继续看doSend()方法:
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
Map failedMessages = new LinkedHashMap();
Transport transport;
try {
transport = getTransport(getSession()); //这里,spring是通过javax.mail.Session的getInstance(Properties props)方法创建的实例。
transport.connect(getHost(), getPort(), getUsername(), getPassword()); //连接到我们配置的邮件服务器。
}
catch (AuthenticationFailedException ex) {
throw new MailAuthenticationException(ex);
}
catch (MessagingException ex) {
// Effectively, all messages failed...
for (int i = 0; i < mimeMessages.length; i++) {
Object original = (originalMessages != null ? originalMessages[i] : mimeMessages[i]);
failedMessages.put(original, ex);
}
throw new MailSendException("Mail server connection failed", ex, failedMessages);
}
try {
for (int i = 0; i < mimeMessages.length; i++) {
MimeMessage mimeMessage = mimeMessages[i];
try {
if (mimeMessage.getSentDate() == null) {
mimeMessage.setSentDate(new Date());
}
String messageId = mimeMessage.getMessageID();
mimeMessage.saveChanges();
if (messageId != null) {
// Preserve explicitly specified message id...
mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId); // 添加消息头部信息
}
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients()); //这里是发送mail的实际代码
}
catch (MessagingException ex) {
Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
failedMessages.put(original, ex);
}
}
}
finally {
try {
transport.close();
}
catch (MessagingException ex) {
if (!failedMessages.isEmpty()) {
throw new MailSendException("Failed to close server connection after message failures", ex,
failedMessages);
}
else {
throw new MailSendException("Failed to close server connection after message sending", ex);
}
}
}
if (!failedMessages.isEmpty()) {
throw new MailSendException(failedMessages);
}
}
看一下创建Session实例的org.springframework.mail.javamail.JavaMailSenderImpl类的getSession()方法:
public synchronized Session getSession() {
if (this.session == null) {
this.session = Session.getInstance(this.javaMailProperties);
}
return this.session;
}
这里并没有真正的创建Session实例,而是执行了javax.mail.Session中的getInstance()方法来创建实例的。
public static Session getInstance(Properties props) {
return new Session(props, null);
}
到这里,从建立Session,到解析字符邮件地址为Address类型,去构造消息Message实例,最后通过Transport类的send方法发送消息。spring中的mail发送邮件细节已经全部完毕了。那么,apache中的commons-email,发送邮件的原理也就彼此彼此!