天天看點

java基于javax.mail的郵件發送器,可發送本地圖檔,可帶附件

所需jar包:連結:https://pan.baidu.com/s/1DSI5KuspG80_FaVjtKiwkg 提取碼:z67j 

本人學生黨,事情發生在做java畢業設計時,當時想着在注冊子產品中加個驗證,但是網上的那些短信驗證碼發送大多數是要收費的,怎麼辦呢?于是就把目光投向了免費的郵箱,我先在網上找了一個工具類,測試驗證碼發送成功。

既然能發送了,就想要搞特殊一點,例如發送成html代碼美化一下、加些圖檔之類的。經測試,那個工具類無法完成,當時就放棄了這個想法,因為在實習,時間不是很充裕。

既然現在有時間了,當然要看一下怎麼實作更多的功能,于是又在網上找些代碼學習,寫出了如下代碼:

package com.geecke.tools.mail;

import java.io.Serializable;
import java.util.Date;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message.RecipientType;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

/**
 * 郵件發送器
 * 
 * JavaMail 版本: 1.6.0 
 * JDK 版本: JDK 1.8
 * 
 * @author iu_chang
 * @version 3.2
 *
 */
public class MailTransmitter implements Serializable {
	private static final long serialVersionUID = 1L;
	/** 發件人賬号 */
	private String account;
	/** 發件人名稱 */
	private String name;
	/** 發件人密碼或授權碼 */
	private String password;
	/** SMTP伺服器位址 */
	private String host;
	/** 郵件編碼 */
	private String encoding;

	/**
	 * 建立一個編碼為UTF-8的郵件發送器
	 * 
	 * @param account
	 *            用來發送郵件的賬号
	 * @param name
	 *            用來發送郵件的賬号的名稱
	 * @param password
	 *            賬号對應的密碼<br>
	 *            如果該郵箱服務商規定第三方需要使用授權碼,則此處應填寫授權碼
	 * @param host
	 *            郵箱的smtp伺服器位址<br>
	 *            一般格式是smtp.xxx.com,例如網易163的是:smtp.163.com<br>
	 *            <br>
	 *            注:需手動開啟POP3/SMTP/IMAP服務
	 */
	public MailTransmitter(String account, String name, String password, String host) {
		this.account = account;
		this.name = name;
		this.password = password;
		this.host = host;
		this.encoding = "UTF-8";
	}

	/**
	 * 建立一個郵件發送器
	 * 
	 * @param account
	 *            用來發送郵件的賬号
	 * @param name
	 *            用來發送郵件的賬号的名稱
	 * @param password
	 *            賬号對應的密碼<br>
	 *            如果該郵箱服務商規定第三方需要使用授權碼,則此處應填寫授權碼
	 * @param host
	 *            郵箱的smtp伺服器位址<br>
	 *            一般格式是smtp.xxx.com,例如網易163的是:smtp.163.com<br>
	 *            <br>
	 *            注:需手動開啟POP3/SMTP/IMAP服務
	 * @param encoding
	 *            欲發送郵件的編碼
	 */
	public MailTransmitter(String account, String name, String password, String host, String encoding) {
		this.account = account;
		this.name = name;
		this.password = password;
		this.host = host;
		this.encoding = encoding;
	}

	public String getAccount() {
		return account;
	}

	public MailTransmitter setAccount(String account) {
		this.account = account;
		return this;
	}

	public String getPassword() {
		return password;
	}

	public MailTransmitter setPassword(String password) {
		this.password = password;
		return this;
	}

	public String getHost() {
		return host;
	}

	public MailTransmitter setHost(String host) {
		this.host = host;
		return this;
	}

	public String getEncoding() {
		return encoding;
	}

	public MailTransmitter setEncoding(String encoding) {
		this.encoding = encoding;
		return this;
	}

	/**
	 * 根據内容擷取MimeBodyPart
	 * 
	 * @param content
	 *            文本内容,如果引用本地檔案請使用src='cid:image_fairy_tail'的形式<br>
	 *            網絡檔案則忽略images參數
	 * @param isCode
	 *            是否為html代碼<br>
	 *            如果為false,則發送純文字,且files參數無效
	 * @param files
	 *            本地圖檔加載,數組第一個元素為檔案全路徑,第二個元素為cid名稱,cid是content的引用
	 * 
	 * @return 單個part節點
	 * @throws Exception
	 */
	public MimeBodyPart getPart(String content, Boolean isCode, String[]... files) throws Exception {
		MimeBodyPart part = new MimeBodyPart();
		if (!isCode) {// 如果為false,則發送純文字
			part.setContent(content, "text/plain;charset=" + this.encoding);
			return part;
		}
		// 建立一個大節點
		MimeMultipart mimeMultipart = new MimeMultipart();

		// 解析images生成part
		for (String[] file : files) {
			// 建立檔案節點
			MimeBodyPart filePart = new MimeBodyPart();
			// 讀入本地檔案
			DataHandler data = new DataHandler(new FileDataSource(file[0]));
			// 将檔案資料添加到檔案節點
			filePart.setDataHandler(data);
			// 為檔案節點設定一個唯一編号(在content将引用該ID)
			filePart.setContentID(file[1]);
			// 将該檔案添加至大節點
			mimeMultipart.addBodyPart(filePart);
		}

		// 建立文本節點
		MimeBodyPart textPart = new MimeBodyPart();
		// 将文本加入至節點
		textPart.setContent(content, "text/html;charset=" + this.encoding);
		// 将節點整合到大節點
		mimeMultipart.addBodyPart(textPart);
		// 設定節點關系為關聯
		mimeMultipart.setSubType("related");
		// 将大節點封裝成節點
		part.setContent(mimeMultipart);
		return part;
	}

	/**
	 * 擷取單個附件節點
	 * 
	 * @param file
	 *            附件全路徑
	 * @param name
	 *            附件名,傳入null則使用file的名稱
	 * @return 單個part節點
	 * @throws Exception
	 */
	public MimeBodyPart getPart(String file, String name) throws Exception {
		// 建立附件節點
		MimeBodyPart part = new MimeBodyPart();
		// 讀取本地檔案
		DataHandler data = new DataHandler(new FileDataSource(file));
		// 将附件資料添加到附件節點
		part.setDataHandler(data);
		// 設定附件名稱(需要編碼)
		if (name == null || "".equals(name)) {// 如果附件名為null或"",則使用file檔案名
			part.setFileName(MimeUtility.encodeText(data.getName()));
			return part;
		}
		part.setFileName(MimeUtility.encodeText(name));
		return part;
	}

	/**
	 * 得到收件人資訊
	 * 
	 * @param receiver
	 *            收件人位址
	 * @return InternetAddress[]
	 * @throws Exception
	 */
	public InternetAddress[] getReceivers(String... receiver) throws Exception {
		if (receiver.length < 0) {
			throw new RuntimeException("收件人為空");
		}
		// 将字元串數組轉為收件人數組
		InternetAddress[] receiverArray = new InternetAddress[receiver.length];
		for (int i = 0; i < receiverArray.length; i++) {
			receiverArray[i] = new InternetAddress(receiver[i]);
		}
		return receiverArray;
	}

	/**
	 * 發送郵件
	 * 
	 * @param receivers
	 *            收件人數組,使用getReceivers()方法獲得
	 * @param subject
	 *            郵件主題
	 * @param recipientType
	 *            發送類型<br>
	 *            普通:RecipientType.TO<br>
	 *            抄送:RecipientType.CC<br>
	 *            密送:RecipientType.BCC
	 * @param parts
	 *            節點,使用getPart()方法獲得
	 * @throws Exception
	 */
	public void send(InternetAddress[] receivers, String subject, RecipientType recipientType, MimeBodyPart... parts)
			throws Exception {
		// 建立會話參數
		Properties props = new Properties();
		// 設定使用的協定(JavaMail規範要求)
		props.setProperty("mail.transport.protocol", "smtp");
		// 設定發件人的郵箱的SMTP伺服器位址
		props.setProperty("mail.smtp.host", this.host);
		// 設定需要請求認證
		props.setProperty("mail.smtp.auth", "true");

		// 根據會話參數建立會話對象, 用于和郵件伺服器互動
		Session session = Session.getInstance(props);
		// 設定為debug模式,可以檢視詳細的發送 log
		session.setDebug(true);

		// 設定發件人資訊
		InternetAddress sender = new InternetAddress(this.account, this.name, this.encoding);

		// 建立一封郵件
		MimeMessage message = createMimeMessage(session, subject, RecipientType.TO, sender, receivers, parts);

		// 儲存到本地檢視
		// message.writeTo(FileOutputStream);

		// 根據Session擷取郵件傳輸對象
		Transport transport = session.getTransport();
		// 使用郵箱賬号和密碼連接配接郵件伺服器
		// 這裡認證的郵箱必須與message中的發件人郵箱一緻,否則報錯
		transport.connect(this.account, this.password);
		// 發送郵件,發到所有的收件位址,message.getAllRecipients()擷取到的是在建立郵件對象時添加發送類型
		transport.sendMessage(message, message.getAllRecipients());

		// 關閉連接配接
		transport.close();
	}

	/**
	 * 建立一封郵件
	 * 
	 * @param session
	 *            用于和郵件伺服器互動的會話
	 * @param subject
	 *            郵件主題
	 * @param recipientType
	 *            發送類型:<br>
	 *            普通:RecipientType.TO<br>
	 *            抄送:RecipientType.CC<br>
	 *            密送:RecipientType.BCC
	 * @param sender
	 *            發件人郵箱
	 * @param receivers
	 *            收件人郵箱數組
	 * @param parts
	 *            郵件内容節點
	 * @return 建立好的郵件對象
	 * @throws Exception
	 */
	private MimeMessage createMimeMessage(Session session, String subject, RecipientType recipientType,
			InternetAddress sender, InternetAddress[] receivers, MimeBodyPart... parts) throws Exception {
		if (receivers.length < 0) {
			throw new RuntimeException("收件人為空");
		}
		// 建立郵件對象
		MimeMessage message = new MimeMessage(session);
		// 設定發件人
		message.setFrom(sender);
		// 設定收件人
		for (InternetAddress receiver : receivers) {
			message.addRecipient(recipientType, receiver);
		}
		// 設定郵件主題
		message.setSubject(subject, this.encoding);

		// 建立大節點
		MimeMultipart multipart = new MimeMultipart();
		// 将傳入的内容節點依次添加進大節點
		for (MimeBodyPart part : parts) {
			multipart.addBodyPart(part);
		}
		// 設定節點關系,不設定則為混合:mixed,可以設定為關聯:related
		multipart.setSubType("mixed");
		// 設定郵件内容
		message.setContent(multipart);

		// 設定發件時間
		message.setSentDate(new Date());

		// 儲存所有設定
		message.saveChanges();
		return message;
	}

	@Override
	public String toString() {
		return "MailTransmitter [account=" + account + ", name=" + name + ", password=" + password + ", host=" + host
				+ ", encoding=" + encoding + "]";
	}

}
           

測試方法如下:

public static void main(String[] args) throws Exception {
		MailTransmitter mailTransmitter = new MailTransmitter("", "郵件發送器", "","smtp.163.com");
		// 發送一封普通郵件
		// 設定内容
		// MimeBodyPart part = mailTransmitter.getPart("這是一封普通郵件<br />html标簽無效", false);
		// 設定收件人
		InternetAddress[] receivers = mailTransmitter.getReceivers("","");
		// 發送
		// mailTransmitter.send(receivers, "郵件測試", RecipientType.TO, part);

		// 發送一封帶圖檔的郵件
		// 設定圖檔,id盡量不要用數字,測試時image1和image2報554 DT:SPM錯誤,即網易垃圾郵件判定
		// String[][] images = { { "E:/image.png", "my_image" }, { "E:/2.png", "my_img" } };
		// 設定内容
		// 此處删除body和前面标簽會報554 DT:SPM錯誤
		// MimeBodyPart part = mailTransmitter.getPart(
		//		"<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title></title></head><body>這是一封超文本郵件<br />html标簽有效<img src='cid:my_image' /><img src='cid:my_img' /><img src='https://www.java.com/feo-cdn/r/_/YWcerH870.jpg' /></body></html>",
		//		true, images);
		
		// 群發帶附件的郵件,測試密送
		// 設定内容
		MimeBodyPart part = mailTransmitter.getPart("這是一封帶2個附件的郵件<br />請主意查收", true);
		// 發送
		mailTransmitter.send(receivers, "郵件測試", RecipientType.BCC, part,mailTransmitter.getPart("E:/image.png", "圖檔1"),mailTransmitter.getPart("E:/2.png", "圖檔2"));
	}
           

測試結果如下:

普通郵件測試:

java基于javax.mail的郵件發送器,可發送本地圖檔,可帶附件

超文本郵件測試:

java基于javax.mail的郵件發送器,可發送本地圖檔,可帶附件

群發帶附件的郵件測試:

java基于javax.mail的郵件發送器,可發送本地圖檔,可帶附件
java基于javax.mail的郵件發送器,可發送本地圖檔,可帶附件