上一篇文章我們用寫了一個Java Mail 的Demo,相信你已經可以用那個例子來傳送郵件了。但是Demo 有很多的問題。
首先每次傳送需要配置的東西很多,包括髮件人的郵箱和密碼、smtp伺服器和SMTP埠號等資訊。其次,沒有將傳送和郵件內容相分離。按照單一職責原則,應該有且僅有一個原因引起類的變更[1]。最後一個問題是,我們的程式碼不僅自己用,也很可能讓別人呼叫。別人呼叫的時候不想去了解郵件傳送的細節,呼叫的人只想傳儘量少的引數獲得預期的效果。因此讓Demo變成可以使用的程式碼需要我們重新設計程式碼的結構。
從Demo中我們可以抽象出兩種型別的POJO,也就是發件人和郵件。你可能會問收件人怎麼辦?收件人可以跟郵件POJO放在一起嗎?
仔細思考下我們就知道,郵件和收件人應該是分開的。因為如果郵件和收件人放在一起,那麼就意味著我的一封郵件只能傳送給特定的人了,而實際上我們會把相同的郵件傳送給不同的收件人。因此收件人只要作為傳送時的引數就可以了。
1.發件人POJO
此處的程式碼我引用了CSDN上一篇博文JAVA郵件傳送的簡單實現
/**
* @Title: MailAuthenticator
* @author: ykgao
* @description:
* @date: 2017-10-11 下午04:55:37
*/
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
/**
* 伺服器郵箱登入驗證
*
* @author MZULE
*
*/
public class MailAuthenticator extends Authenticator {
/**
* 使用者名稱(登入郵箱)
*/
private String username;
/**
* 密碼
*/
private String password;
/**
* 初始化郵箱和密碼
*
* @param username 郵箱
* @param password 密碼
*/
public MailAuthenticator(String username, String password) {
this.username = username;
this.password = password;
}
String getPassword() {
return password;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
String getUsername() {
return username;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
}
複製程式碼
2.郵件POJO
用於儲存郵件主題和內容。
/**
* @Title: SimpleMail
* @author: ykgao
* @description:
* @date: 2017-10-11 下午04:56:27
*/
public class SimpleMail {
/** 郵件主題 */
public String Subject;
/** 郵件內容 */
public String Content;
/**
* @return the subject
*/
public String getSubject() {
return Subject;
}
/**
* @param subject
* the subject to set
*/
public void setSubject(String subject) {
Subject = subject;
}
/**
* @return the content
*/
public String getContent() {
return Content;
}
/**
* @param content
* the content to set
*/
public void setContent(String content) {
Content = content;
}
}
複製程式碼
3.郵件傳送
設計好了POJO,我們現在需要當然是傳送郵件了。在Demo中我們需要配置SMTP伺服器,但是我們使用郵箱傳送郵件的時候並不需要填寫SMTP伺服器。其實SMTP伺服器大多數的格式是:smtp.emailType.com。此處emailType 就是你的郵箱型別也就是@後面跟的名稱。比如163郵箱就是163。不過這個方法也不是萬能的,因為outlook郵箱的smtp伺服器就不是這個格式,而是smtp-mail.outlook.com ,所以我單獨為outlook郵箱寫了個例外。 我們還需要群分郵件的功能。這個設計起來很容易,只需要一個單人傳送的過載方法,其收件人的引數可以是一個List。 為了減少介面的引數個數,我們把SMTP埠預設為587。
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.List;
import java.util.Properties;
import javaMailDevelopment.SimpleMail;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import com.sun.mail.util.MailSSLSocketFactory;
/**
* @Title: SimpleMailSender
* @author: ykgao
* @description: 郵件傳送器
* @date: 2017-10-11 下午04:54:50
*/
public class SimpleMailSender {
/**
* 傳送郵件的props檔案
*/
private final transient Properties props = System.getProperties();
/**
* 郵件伺服器登入驗證
*/
private transient MailAuthenticator authenticator;
/**
* 郵箱session
*/
private transient Session session;
/**
* 初始化郵件傳送器
*
* @param smtpHostName
* SMTP郵件伺服器地址
* @param username
* 傳送郵件的使用者名稱(地址)
* @param password
* 傳送郵件的密碼
*/
public SimpleMailSender(final String smtpHostName, final String username, final String password) {
init(username, password, smtpHostName);
}
/**
* 初始化郵件傳送器
*
* @param username
* 傳送郵件的使用者名稱(地址),並以此解析SMTP伺服器地址
* @param password
* 傳送郵件的密碼
*/
public SimpleMailSender(final String username, final String password) {
// 通過郵箱地址解析出smtp伺服器,對大多數郵箱都管用
String smtpHostName = "smtp." + username.split("@")[1];
if (username.split("@")[1].equals("outlook.com")) {
smtpHostName = "smtp-mail.outlook.com";
}
init(username, password, smtpHostName);
}
/**
* 初始化
*
* @param username
* 傳送郵件的使用者名稱(地址)
* @param password
* 密碼
* @param smtpHostName
* SMTP主機地址
*/
private void init(String username, String password, String smtpHostName) {
// 初始化props
props.setProperty("mail.transport.protocol", "smtp"); // 使用的協議(JavaMail規範要求)
props.setProperty("mail.smtp.host", smtpHostName); // 發件人的郵箱的 SMTP 伺服器地址
props.setProperty("mail.smtp.auth", "true"); // 需要請求認證
final String smtpPort = "587";
props.setProperty("mail.smtp.port", smtpPort);
// props.setProperty("mail.smtp.socketFactory.class",
// "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.starttls.enable", "true");
props.setProperty("mail.smtp.socketFactory.port", smtpPort);
// 驗證
authenticator = new MailAuthenticator(username, password);
// 建立session
session = Session.getInstance(props, authenticator);
session.setDebug(true);
}
/**
* 傳送郵件
*
* @param recipient
* 收件人郵箱地址
* @param subject
* 郵件主題
* @param content
* 郵件內容
* @throws AddressException
* @throws MessagingException
* @throws UnsupportedEncodingException
*/
public void send(String recipient, String subject, Object content) throws Exception {
// 建立mime型別郵件
final MimeMessage message = new MimeMessage(session);
// 設定發信人
message.setFrom(new InternetAddress(authenticator.getUsername()));
// 設定收件人
message.setRecipient(RecipientType.TO, new InternetAddress(recipient));
// 設定主題
message.setSubject(subject);
// 設定郵件內容
message.setContent(content.toString(), "text/html;charset=utf-8");
// 傳送
Transport.send(message);
}
/**
* 群發郵件
*
* @param recipients
* 收件人們
* @param subject
* 主題
* @param content
* 內容
* @throws AddressException
* @throws MessagingException
*/
public void send(List<String> recipients, String subject, Object content)
throws AddressException, MessagingException {
// 建立mime型別郵件
final MimeMessage message = new MimeMessage(session);
// 設定發信人
message.setFrom(new InternetAddress(authenticator.getUsername()));
// 設定收件人們
final int num = recipients.size();
InternetAddress[] addresses = new InternetAddress[num];
for (int i = 0; i < num; i++) {
addresses[i] = new InternetAddress(recipients.get(i));
}
message.setRecipients(RecipientType.TO, addresses);
// 設定主題
message.setSubject(subject);
// 設定郵件內容
message.setContent(content.toString(), "text/html;charset=utf-8");
// 傳送
Transport.send(message);
}
/**
* 傳送郵件
*
* @param recipient
* 收件人郵箱地址 @param mail 郵件物件 @throws AddressException @throws
* MessagingException @throws
*/
public void send(String recipient, SimpleMail mail) throws Exception {
send(recipient, mail.getSubject(), mail.getContent());
}
/**
* 群發郵件
*
* @param recipients
* 收件人們
* @param mail
* 郵件物件
* @throws AddressException
* @throws MessagingException
*/
public void send(List<String> recipients, SimpleMail mail) throws AddressException, MessagingException {
send(recipients, mail.getSubject(), mail.getContent());
}
}
複製程式碼
4.測試程式碼
程式碼寫完了,現在需要測試下程式碼是否可行。
import java.util.ArrayList;
import java.util.List;
/**
* @Title: testMail
* @author: ykgao
* @description:
* @date: 2017-10-11 下午02:13:02
*
*/
public class testMail {
public static void main(String[] args) throws Exception {
/** 建立一個郵件傳送者*/
SimpleMailSender simpleMailSender=new SimpleMailSender("Example@outlook.com", "password");
/** 建立一封郵件*/
SimpleMail mail=new SimpleMail();
mail.setContent("This is a test email.");
mail.setSubject("We want to invite you to our home.");
/**
List<String> recipients=new ArrayList<String>();
recipients.add("Example1@qq.com");
recipients.add("Example2@qq.com");
recipients.add("Example2@qq.com");
simpleMailSender.send(recipients, mail);
}
}
複製程式碼
再次感謝小瓶子的部落格,我的大部分程式碼都是從他的部落格基礎上修改的。
引自《設計模式之禪》,秦小波 著 ↩︎