結合Spring傳送郵件的四種正確姿勢,你知道幾種?

SnailClimb發表於2019-03-04

一 前言

測試所使用的環境

測試使用的環境是企業主流的SSM 框架即 SpringMVC+Spring+Mybatis。為了節省時間,我直接使用的是我上次的“SSM專案中整合Echarts開發”該專案已經搭建完成的SSM環境。

標題說的四種姿勢指的是哪四種姿勢?

  1. 傳送text格式的郵件
  2. 傳送HTML格式的郵件
  3. 基於FreeMarker模板引擎傳送郵件
  4. 基於Velocity模板引擎傳送郵件

如何獲取以及執行我的Demo

Github地址:github.com/Snailclimb/…

你可以選擇直接下載或者直接在DOS視窗執行:git clone https://github.com/Snailclimb/J2ee-Advanced.git命令,這樣專案就被拷貝到你的電腦了。

結合Spring傳送郵件的四種正確姿勢,你知道幾種?

然後選擇匯入Maven專案即可(不懂Maven的可以自行百度學習).

二 準備工作

既然要傳送郵件,那麼你首先要提供一個能在第三方軟體上傳送郵件功能的賬號。在這裡,我選擇的網易郵箱賬號。

我拿網易郵箱賬號舉例子,那麼我們如何才能讓你的郵箱賬號可以利用第三方傳送郵件(這裡的第三方就是我們即將編寫的程式)。

大家應該清楚:客戶端和後臺互動資料的時候用到了Http協議,那麼相應的,郵箱傳輸也有自己的一套協議,如SMTP,POP3,IMAP。

開啟POP3/SMTP/IMAP服務

所以,我們第一步首先要去開啟這些服務,如下圖所示:

開啟服務

如果你未開啟該服務的話,執行程式會報如下錯誤(配置檔案中配置的密碼是你的授權碼而不是你登入郵箱的密碼,授權碼是你第三方登入的憑證):

HTTP Status 500 - Request processing failed; nested exception is org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: 550 User has no permission
複製程式碼

JavaMail介紹

我們需要用到的發郵件的核心jar包,所以這裡好好介紹一下。

JavaMail是由Sun定義的一套收發電子郵件的API,不同的廠商可以提供自己的實現類。但它並沒有包含在JDK中,而是作為JavaEE的一部分。廠商所提供的JavaMail服務程式可以有選擇地實現某些郵件協議,常見的郵件協議包括:

  • SMTP:簡單郵件傳輸協議,用於傳送電子郵件的傳輸協議;
  • POP3:用於接收電子郵件的標準協議;
  • IMAP:網際網路訊息協議,是POP3的替代協議。

這三種協議都有對應SSL加密傳輸的協議,分別是SMTPS,POP3S和IMAPS。

我們如果要使用JavaMail的話,需要自己引用相應的jar包,如下圖所示:

		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.4.7</version>
		</dependency>
複製程式碼

相關配置檔案

下圖是除了pom.xml之外用到的其他所有配置檔案

配置檔案

pom.xml

需要用到的jar包。

        <!--spring支援-->
        <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context-support</artifactId>
              <version>5.0.0.RELEASE</version>
        </dependency>
		<!-- 傳送郵件 -->
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.4.7</version>
		</dependency>
		<!-- Freemarker -->
		<dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>2.3.23</version>
		</dependency>
		<!-- velocity模板引擎 -->
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>1.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity-tools</artifactId>
			<version>2.0</version>
		</dependency>
複製程式碼

mail.properties

#伺服器主機名
mail.smtp.host=smtp.163.com
#你的郵箱地址
mail.smtp.username=koushuangbwcx@163.com
#你的授權碼
mail.smtp.password=cSdN153963000
#編碼格式
mail.smtp.defaultEncoding=utf-8
#是否進行使用者名稱密碼校驗
mail.smtp.auth=true
#設定超時時間
mail.smtp.timeout=20000
複製程式碼

如果你的授權碼填寫錯誤的話,會報如下錯誤:

TTP Status 500 - Request processing failed; nested exception is org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: 535 Error: authentication failed
複製程式碼

velocity.properties

input.encoding=UTF-8  
output.encoding=UTF-8  
contentType=ext/html;charset=UTF-8
directive.foreach.counter.name=loopCounter  
directive.foreach.counter.initial.value=0
複製程式碼

applicationContext-email.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
        http://www.springframework.org/schema/aop    
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

	<!--郵件配置 -->
	<context:property-placeholder location="classpath:mail.properties"
		ignore-unresolvable="true" />

	<!--配置郵件介面 -->
	<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
		<property name="host" value="${mail.smtp.host}" />
		<property name="username" value="${mail.smtp.username}" />
		<property name="password" value="${mail.smtp.password}" />
		<property name="defaultEncoding" value="${mail.smtp.defaultEncoding}" />
		<property name="javaMailProperties">
			<props>
				<prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
				<prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>
			</props>
		</property>
	</bean>
	<!-- freemarker -->
	<bean id="configuration"
		class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
		<property name="templateLoaderPath" value="/WEB-INF/freemarker/" />
		<!-- 設定FreeMarker環境變數 -->
		<property name="freemarkerSettings">
			<props>
				<prop key="default_encoding">UTF-8</prop>
			</props>
		</property>
	</bean>


	<!-- velocity -->
	<bean id="velocityEngine"
		class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
		<property name="resourceLoaderPath" value="/WEB-INF/velocity/" /><!-- 
			模板存放的路徑 -->
		<property name="configLocation" value="classpath:velocity.properties" /><!-- 
			Velocity的配置檔案 -->
	</bean>

</beans>
複製程式碼

三 開始編寫工具類

我這裡說是工具類,其實只是我自己做了簡單的封裝,實際專案使用的話,可能會需要根據需要簡單修改一下。

所有用到的類如下圖所示:

所有用到的類

傳送Text或者HTML格式的郵件的方法

	/**
	 * 
	 * Text或者HTML格式郵件的方法
	 * 
	 * @param text
	 *            要傳送的內容
	 * @param subject
	 *            郵件的主題也就是郵件的標題
	 * @param location
	 *            檔案的地址
	 * @param emailAdress
	 *            目的地
	 * @param javaMailSender
	 *            傳送郵件的核心類(在xml檔案中已經配置好了)
	 * @param type
	 *            如果為true則代表傳送HTML格式的文字
	 * @return
	 * @throws TemplateException
	 */
	public String sendMail(String text, String subject, String location, String emailAdress,
			JavaMailSender javaMailSender, Boolean type) {
		MimeMessage mMessage = javaMailSender.createMimeMessage();// 建立郵件物件
		MimeMessageHelper mMessageHelper;
		Properties prop = new Properties();
		try {
			// 從配置檔案中拿到發件人郵箱地址
			prop.load(this.getClass().getResourceAsStream("/mail.properties"));
			String from = prop.get("mail.smtp.username") + "";
			mMessageHelper = new MimeMessageHelper(mMessage, true, "UTF-8");
			// 發件人郵箱
			mMessageHelper.setFrom(from);
			// 收件人郵箱
			mMessageHelper.setTo(emailAdress);
			// 郵件的主題也就是郵件的標題
			mMessageHelper.setSubject(subject);
			// 郵件的文字內容,true表示文字以html格式開啟
			if (type) {
				mMessageHelper.setText(text, true);
			} else {
				mMessageHelper.setText(text, false);
			}

			// 通過檔案路徑獲取檔名字
			String filename = StringUtils.getFileName(location);
			// 定義要傳送的資源位置
			File file = new File(location);
			FileSystemResource resource = new FileSystemResource(file);
			FileSystemResource resource2 = new FileSystemResource("D:/email.txt");
			mMessageHelper.addAttachment(filename, resource);// 在郵件中新增一個附件
			mMessageHelper.addAttachment("JavaApiRename.txt", resource2);//
			// 在郵件中新增一個附件
			javaMailSender.send(mMessage);// 傳送郵件
		} catch (MessagingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "傳送成功";
	}
複製程式碼

我在sendMail()方法中新增了一個boolean型別的變數type作為標誌,如果為ture就表示傳送html格式的郵件否則直接傳送text格式的郵件。實現起來很簡單,我們通過下面的判斷語句就可以實現了

			if (type) {
		        //表示文字以html格式開啟
				mMessageHelper.setText(text, true);
			} else {
				mMessageHelper.setText(text, false);
			}
複製程式碼

效果:

結合Spring傳送郵件的四種正確姿勢,你知道幾種?

基於FreeMarker模板引擎傳送郵件

下圖是我們用到的FreeMarker模板檔案以及Velocity模板檔案的位置。

結合Spring傳送郵件的四種正確姿勢,你知道幾種?

	/**
	 * FreeMarker模板格式的郵件的方法
	 * 
	 * @param subject
	 *            郵件的主題也就是郵件的標題
	 * @param location
	 *            檔案的地址
	 * @param emailAdress
	 *            目的地
	 * @param javaMailSender
	 *            傳送郵件的核心類(在xml檔案中已經配置好了)
	 * @param freeMarkerConfiguration
	 *            freemarker配置管理類
	 * @return
	 * @throws TemplateException
	 */
	public String sendMailFreeMarker(String subject, String location, String emailAdress, JavaMailSender javaMailSender,
			Configuration freeMarkerConfiguration) {
		MimeMessage mMessage = javaMailSender.createMimeMessage();// 建立郵件物件
		MimeMessageHelper mMessageHelper;
		Properties prop = new Properties();
		try {
			// 從配置檔案中拿到發件人郵箱地址
			prop.load(this.getClass().getResourceAsStream("/mail.properties"));
			String from = prop.get("mail.smtp.username") + "";
			mMessageHelper = new MimeMessageHelper(mMessage, true);
			// 發件人郵箱
			mMessageHelper.setFrom(from);
			// 收件人郵箱
			mMessageHelper.setTo(emailAdress);
			// 郵件的主題也就是郵件的標題
			mMessageHelper.setSubject(subject);
			// 解析模板檔案
			mMessageHelper.setText(getText(freeMarkerConfiguration), true);
			// 通過檔案路徑獲取檔名字
			String filename = StringUtils.getFileName(location);
			// 定義要傳送的資源位置
			File file = new File(location);
			FileSystemResource resource = new FileSystemResource(file);
			mMessageHelper.addAttachment(filename, resource);// 在郵件中新增一個附件
			javaMailSender.send(mMessage);// 傳送郵件
		} catch (MessagingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "傳送成功";
	}
	
  	/**
	 * 讀取freemarker模板的方法
	 */
	private String getText(Configuration freeMarkerConfiguration) {
		String txt = "";
		try {
			Template template = freeMarkerConfiguration.getTemplate("email.ftl");
			// 通過map傳遞動態資料
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("user", "Snailclimb");
			// 解析模板檔案
			txt = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
			System.out.println("getText()->>>>>>>>>");// 輸出的是HTML格式的文件
			System.out.println(txt);
		} catch (IOException e) {
			// TODO 異常執行塊!
			e.printStackTrace();
		} catch (TemplateException e) {
			// TODO 異常執行塊!
			e.printStackTrace();
		}

		return txt;
	}
複製程式碼

我們通過getText(Configuration freeMarkerConfiguration)方法讀取freemarker模板,返回的格式如下圖所示:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>測試</title>
</head>

<body>
<h1>你好Snailclimb</h1>
</body>
</html>
複製程式碼

其實就是HTML,然後我們就可以像前面傳送HTML格式郵件的方式傳送這端訊息了。

email.ftl

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>測試</title>
</head>

<body>
<h1>你好${user}</h1>
</body>
</html>
複製程式碼

效果:

不知道為啥,騰訊每次把我使用模板引擎發的郵件直接放到垃圾箱。大家如果遇到接收不到郵件,但是又沒報錯的情況,可以看看是不是到了自己郵箱的垃圾箱。

結合Spring傳送郵件的四種正確姿勢,你知道幾種?

基於Velocity模板引擎傳送郵件

	/**
	 * 
	 * @param subject
	 *            郵件主題
	 * @param location
	 *            收件人地址
	 * @param emailAdress
	 *            目的地
	 * @param javaMailSender
	 *            傳送郵件的核心類(在xml檔案中已經配置好了)
	 * @param velocityEngine
	 *            Velocity模板引擎
	 * @return
	 */
	public String sendMailVelocity(String subject, String location, String emailAdress, JavaMailSender javaMailSender,
			VelocityEngine velocityEngine) {
		MimeMessage mMessage = javaMailSender.createMimeMessage();// 建立郵件物件
		MimeMessageHelper mMessageHelper;
		Properties prop = new Properties();
		try {
			// 從配置檔案中拿到發件人郵箱地址
			prop.load(this.getClass().getResourceAsStream("/mail.properties"));
			System.out.println(this.getClass().getResourceAsStream("/mail.properties"));
			String from = prop.get("mail.smtp.username") + "";
			mMessageHelper = new MimeMessageHelper(mMessage, true, "UTF-8");
			// 發件人郵箱
			mMessageHelper.setFrom(from);
			// 收件人郵箱
			mMessageHelper.setTo(emailAdress);
			// 郵件的主題也就是郵件的標題
			mMessageHelper.setSubject(subject);
			Map<String, Object> map = new HashMap<>();
			// 獲取日期並格式化
			Date date = new Date();
			DateFormat bf = new SimpleDateFormat("yyyy-MM-dd E a HH:mm:ss");
			String str = bf.format(date);
			map.put("date", str);
			String content = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "email.vm", "UTF-8", map);
			mMessageHelper.setText(content, true);
			// 通過檔案路徑獲取檔名字
			String filename = StringUtils.getFileName(location);
			// 定義要傳送的資源位置
			File file = new File(location);
			FileSystemResource resource = new FileSystemResource(file);
			mMessageHelper.addAttachment(filename, resource);// 在郵件中新增一個附件
			// mMessageHelper.addAttachment("JavaApiRename.txt", resource2);//
			// 在郵件中新增一個附件
			javaMailSender.send(mMessage);// 傳送郵件
		} catch (MessagingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "傳送成功";
	}
複製程式碼

email.vm

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
 
<body>
<h3>今天的日期是:${date}</h3>

</body>
</html>
複製程式碼

效果:

結合Spring傳送郵件的四種正確姿勢,你知道幾種?

controller層


/**
 * 測試郵件傳送controller
 * @author Snailclimb
 */
@RestController
@RequestMapping("mail")
public class SendMailController {
	@Autowired
	private JavaMailSender javaMailSender;// 在spring中配置的郵件傳送的bean
	@Autowired
	private Configuration configuration;
	@Autowired
	private VelocityEngine velocityEngine;

	// text
	@RequestMapping("send")
	public String sendEmail() {
		EmailUtils emailUtils = new EmailUtils();
		return emailUtils.sendMail("大傻子大傻子大傻子,你好!!!", "傳送給我家大傻子的~", "D:/picture/meizi.jpg", "1361583339@qq.com",
				javaMailSender, false);
	}

	// html
	@RequestMapping("send2")
	public String sendEmail2() {
		EmailUtils emailUtils = new EmailUtils();
		return emailUtils.sendMail(
				"<p>大傻子大傻子大傻子,你好!!!</p><br/>" + "<a href='https://github.com/Snailclimb'>點選開啟我的Github!</a><br/>",
				"傳送給我家大傻子的~", "D:/picture/meizi.jpg", "1361583339@qq.com", javaMailSender, true);
	}

	// freemarker
	@RequestMapping("send3")
	public String sendEmail3() {
		EmailUtils emailUtils = new EmailUtils();
		return emailUtils.sendMailFreeMarker("傳送給我家大傻子的~", "D:/picture/meizi.jpg", "1361583339@qq.com", javaMailSender,
				configuration);

	}

	// velocity
	@RequestMapping("send4")
	public String sendEmail4() {
		EmailUtils emailUtils = new EmailUtils();
		return emailUtils.sendMailVelocity("傳送給我家大傻子的~", "D:/picture/meizi.jpg", "1361583339@qq.com", javaMailSender,
				velocityEngine);

	}
}

複製程式碼

四 總結

上面我們總結了Spring傳送郵件的四種正確姿勢,並且將核心程式碼提供給了大家。程式碼中有我很詳細的註釋,所以我對於程式碼以及相關類的講解很少,感興趣的同學可以自行學習。最後,本專案Github地址:github.com/Snailclimb/…

五 推薦一個自己的開源的後端文件

Java-Guide: Java面試通關手冊(Java學習指南)。(star:1.4k)

Github地址:github.com/Snailclimb/…

文件定位:一個專門為Java後端工程師準備的開源文件,相信不論你是Java新手還是已經成為一名Java工程師都能從這份文件中收穫到一些東西。

你若盛開,清風自來。 歡迎關注我的微信公眾號:“Java面試通關手冊”,一個有溫度的微信公眾號。公眾號有大量資料,回覆關鍵字“1”你可能看到想要的東西哦!

結合Spring傳送郵件的四種正確姿勢,你知道幾種?

相關文章