新聞中心
Spring Boot集成郵件服務(wù)竟如此簡單,快速掌握郵件業(yè)務(wù)類的核心邏輯和企業(yè)郵件的日常服務(wù)。

豐潤ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!
什么是SMTP?
SMTP全稱為Simple Mail Transfer Protocol(簡單郵件傳輸協(xié)議),它是一組用于從源地址到目的地址傳輸郵件的規(guī)范,通過它來控制郵件的中轉(zhuǎn)方式。SMTP認(rèn)證要求必須提供賬號(hào)和密碼才能登陸服務(wù)器,其設(shè)計(jì)目的在于避免用戶受到垃圾郵件的侵?jǐn)_。
什么是IMAP?
IMAP全稱為Internet Message Access Protocol(互聯(lián)網(wǎng)郵件訪問協(xié)議),IMAP允許從郵件服務(wù)器上獲取郵件的信息、下載郵件等。IMAP與POP類似,都是一種郵件獲取協(xié)議。
什么是POP3?
POP3全稱為Post Office Protocol 3(郵局協(xié)議),POP3支持客戶端遠(yuǎn)程管理服務(wù)器端的郵件。POP3常用于“離線”郵件處理,即允許客戶端下載服務(wù)器郵件,然后服務(wù)器上的郵件將會(huì)被刪除。目前很多POP3的郵件服務(wù)器只提供下載郵件功能,服務(wù)器本身并不刪除郵件,這種屬于改進(jìn)版的POP3協(xié)議。
IMAP和POP3協(xié)議有什么不同呢?
兩者最大的區(qū)別在于,IMAP允許雙向通信,即在客戶端的操作會(huì)反饋到服務(wù)器上,例如在客戶端收取郵件、標(biāo)記已讀等操作,服務(wù)器會(huì)跟著同步這些操作。而對(duì)于POP協(xié)議雖然也允許客戶端下載服務(wù)器郵件,但是在客戶端的操作并不會(huì)同步到服務(wù)器上面的,例如在客戶端收取或標(biāo)記已讀郵件,服務(wù)器不會(huì)同步這些操作。
什么是JavaMailSender和JavaMailSenderImpl?
JavaMailSender和JavaMailSenderImpl 是Spring官方提供的集成郵件服務(wù)的接口和實(shí)現(xiàn)類,以簡單高效的設(shè)計(jì)著稱,目前是Java后端發(fā)送郵件和集成郵件服務(wù)的主流工具。
如何通過JavaMailSenderImpl發(fā)送郵件?
非常簡單,直接在業(yè)務(wù)類注入JavaMailSenderImpl并調(diào)用send方法發(fā)送郵件。其中簡單郵件可以通過SimpleMailMessage來發(fā)送郵件,而復(fù)雜的郵件(例如添加附件)可以借助MimeMessageHelper來構(gòu)建MimeMessage發(fā)送郵件。例如:
- @Autowired
- private JavaMailSenderImpl mailSender;
- public void sendMail() throws MessagingException {
- SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
- simpleMailMessage.setFrom("[email protected]");
- simpleMailMessage.setTo("[email protected]");
- simpleMailMessage.setSubject("Happy New Year");
- simpleMailMessage.setText("新年快樂!");
- mailSender.send(simpleMailMessage);
- MimeMessage mimeMessage = mailSender.createMimeMessage();
- MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
- messageHelper.setFrom("[email protected]");
- messageHelper.setTo("[email protected]");
- messageHelper.setSubject("Happy New Year");
- messageHelper.setText("新年快樂!");
- messageHelper.addInline("doge.gif", new File("xx/xx/doge.gif"));
- messageHelper.addAttachment("work.docx", new File("xx/xx/work.docx"));
- mailSender.send(mimeMessage);
- }
為什么`JavaMailSenderImpl` 能夠開箱即用 ?
所謂開箱即用其實(shí)就是基于官方內(nèi)置的自動(dòng)配置,翻看源碼可知曉郵件自動(dòng)配置類(MailSenderPropertiesConfiguration) 為上下文提供了郵件服務(wù)實(shí)例(JavaMailSenderImpl)。具體源碼如下:
- @Configuration
- @ConditionalOnProperty(prefix = "spring.mail", name = "host")
- class MailSenderPropertiesConfiguration {
- private final MailProperties properties;
- MailSenderPropertiesConfiguration(MailProperties properties) {
- this.properties = properties;
- }
- @Bean
- @ConditionalOnMissingBean
- public JavaMailSenderImpl mailSender() {
- JavaMailSenderImpl sender = new JavaMailSenderImpl();
- applyProperties(sender);
- return sender;
- }
其中MailProperties是關(guān)于郵件服務(wù)器的配置信息,具體源碼如下:
- @ConfigurationProperties(prefix = "spring.mail")
- public class MailProperties {
- private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
- private String host;
- private Integer port;
- private String username;
- private String password;
- private String protocol = "smtp";
- private Charset defaultEncoding = DEFAULT_CHARSET;
- private Map
properties = new HashMap<>(); - }
一、開啟郵件服務(wù)
登陸網(wǎng)易郵箱163,在設(shè)置中打開并勾選POP3/SMTP/IMAP服務(wù),然后會(huì)得到一個(gè)授權(quán)碼,這個(gè)郵箱和授權(quán)碼將用作登陸認(rèn)證。
二、配置郵件服務(wù)
首先咱們通過 Spring Initializr 創(chuàng)建工程springboot-send-mail,如圖所示:推薦看下:年輕人的第一個(gè) Spring Boot 應(yīng)用。
然后在pom.xml 引入web、thymeleaf 和spring-boot-starter-mail等相關(guān)依賴。例如:
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-mail org.webjars webjars-locator-core org.webjars jquery 3.3.1 org.webjars bootstrap 3.3.7 org.springframework.boot spring-boot-devtools runtime org.springframework.boot spring-boot-starter-test test
根據(jù)前面提到的配置項(xiàng)(MailProperties)填寫相關(guān)配置信息,其中spring.mail.username 表示連接郵件服務(wù)器時(shí)認(rèn)證的登陸賬號(hào),可以是普通的手機(jī)號(hào)或者登陸賬號(hào),并非一定是郵箱,為了解決這個(gè)問題,推薦大家在spring.mail. properties.from填寫郵件發(fā)信人即真實(shí)郵箱。
然后在application.yml添加如下配置:
- spring:
- mail:
- host: smtp.163.com #SMTP服務(wù)器地址
- username: socks #登陸賬號(hào)
- password: 123456 #登陸密碼(或授權(quán)碼)
- properties:
- from: [email protected] #郵件發(fā)信人(即真實(shí)郵箱)
- thymeleaf:
- cache: false
- prefix: classpath:/views/
- servlet:
- multipart:
- max-file-size: 10MB #限制單個(gè)文件大小
- max-request-size: 50MB #限制請(qǐng)求總量
透過前面的進(jìn)階知識(shí),我們知道在發(fā)送郵件前,需要先構(gòu)建 SimpleMailMessage或 MimeMessage 郵件信息類來填寫郵件標(biāo)題、郵件內(nèi)容等信息,最后提交給JavaMailSenderImpl發(fā)送郵件,這樣看起來沒什么問題,也能實(shí)現(xiàn)既定目標(biāo),但在實(shí)際使用中會(huì)出現(xiàn)大量零散和重復(fù)的代碼,還不便于保存郵件到數(shù)據(jù)庫。
那么優(yōu)雅的發(fā)送郵件應(yīng)該是如何的呢?應(yīng)該屏蔽掉這些構(gòu)建信息和發(fā)送郵件的細(xì)節(jié),不管是簡單還是復(fù)雜郵件,都可以通過統(tǒng)一的API來發(fā)送郵件。例如:mailService.send(mailVo) 。
例如通過郵件信息類(MailVo) 來保存發(fā)送郵件時(shí)的郵件主題、郵件內(nèi)容等信息 :
- package com.hehe.vo;
- public class MailVo {
- private String id;
- private String from;
- private String to;
- private String subject;
- private String text;
- private Date sentDate;
- private String cc;
- private String bcc;
- private String status;
- private String error;
- @JsonIgnore
- private MultipartFile[] multipartFiles;
- }
三、發(fā)送郵件和附件
除了發(fā)送郵件之外,還包括檢測郵件和保存郵件等操作,例如:
- 檢測郵件 checkMail(); 首先校驗(yàn)郵件收信人、郵件主題和郵件內(nèi)容這些必填項(xiàng),若為空則拒絕發(fā)送。
- 發(fā)送郵件 sendMimeMail(); 其次通過MimeMessageHelper來解析MailVo并構(gòu)建MimeMessage傳輸郵件。
- 保存郵件 sendMimeMail(); 最后將郵件保存到數(shù)據(jù)庫,便于統(tǒng)計(jì)和追查郵件問題。
本案例郵件業(yè)務(wù)類 MailService 的具體源碼如下:
- package com.hehe.service;
- @Service
- public class MailService {
- private Logger logger = LoggerFactory.getLogger(getClass());
- @Autowired
- private JavaMailSenderImpl mailSender;
- public MailVo sendMail(MailVo mailVo) {
- try {
- checkMail(mailVo);
- sendMimeMail(mailVo);
- return saveMail(mailVo);
- } catch (Exception e) {
- logger.error("發(fā)送郵件失敗:", e);
- mailVo.setStatus("fail");
- mailVo.setError(e.getMessage());
- return mailVo;
- }
- }
- private void checkMail(MailVo mailVo) {
- if (StringUtils.isEmpty(mailVo.getTo())) {
- throw new RuntimeException("郵件收信人不能為空");
- }
- if (StringUtils.isEmpty(mailVo.getSubject())) {
- throw new RuntimeException("郵件主題不能為空");
- }
- if (StringUtils.isEmpty(mailVo.getText())) {
- throw new RuntimeException("郵件內(nèi)容不能為空");
- }
- }
- private void sendMimeMail(MailVo mailVo) {
- try {
- MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
- mailVo.setFrom(getMailSendFrom());
- messageHelper.setFrom(mailVo.getFrom());
- messageHelper.setTo(mailVo.getTo().split(","));
- messageHelper.setSubject(mailVo.getSubject());
- messageHelper.setText(mailVo.getText());
- if (!StringUtils.isEmpty(mailVo.getCc())) {
- messageHelper.setCc(mailVo.getCc().split(","));
- }
- if (!StringUtils.isEmpty(mailVo.getBcc())) {
- messageHelper.setCc(mailVo.getBcc().split(","));
- }
- if (mailVo.getMultipartFiles() != null) {
- for (MultipartFile multipartFile : mailVo.getMultipartFiles()) {
- messageHelper.addAttachment(multipartFile.getOriginalFilename(), multipartFile);
- }
- }
- if (StringUtils.isEmpty(mailVo.getSentDate())) {
- mailVo.setSentDate(new Date());
- messageHelper.setSentDate(mailVo.getSentDate());
- }
- mailSender.send(messageHelper.getMimeMessage());
- mailVo.setStatus("ok");
- logger.info("發(fā)送郵件成功:{}->{}", mailVo.getFrom(), mailVo.getTo());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- private MailVo saveMail(MailVo mailVo) {
- return mailVo;
- }
- public String getMailSendFrom() {
- return mailSender.getJavaMailProperties().getProperty("from");
- }
- }
搞定了發(fā)送郵件最核心的業(yè)務(wù)邏輯,接下來咱們寫一個(gè)簡單頁面用來發(fā)送郵件。Spring Boot 如何快速改造老項(xiàng)目?推薦看下。
首先寫好跟頁面交互的控制器 MailController,具體源碼如下:
- @RestController
- public class MailController {
- @Autowired
- private MailService mailService;
- @GetMapping("/")
- public ModelAndView index() {
- ModelAndView mv = new ModelAndView("mail/sendMail");
- mv.addObject("from", mailService.getMailSendFrom());
- return mv;
- }
- @PostMapping("/mail/send")
- public MailVo sendMail(MailVo mailVo, MultipartFile[] files) {
- mailVo.setMultipartFiles(files);
- return mailService.sendMail(mailVo);
- }
- }
然后在/resources/views/mail目錄新建sendMail.html,具體源碼如下:
發(fā)送郵件
四、測試發(fā)送郵件
如果是初學(xué)者,建議大家先下載源碼,修改配置后運(yùn)行工程,成功后再自己重新寫一遍代碼,這樣有助于加深記憶。關(guān)注公眾號(hào):Java技術(shù)棧,回復(fù):boot,獲取 Spring Boot 系列教程。
啟動(dòng)工程并訪問:http://localhost:8080 然后可以看到發(fā)送郵件的主界面如下:
然后填寫你的小號(hào)郵箱,點(diǎn)擊發(fā)送郵件,若成功則可以登陸小號(hào)郵箱查看郵件和剛才上傳的附件。
五、常見失敗編碼
如果企業(yè)定制了郵件服務(wù)器,自然會(huì)記錄郵件日志,根據(jù)錯(cuò)誤編碼存儲(chǔ)日志有利于日常維護(hù)。1 分鐘教會(huì)你用 Spring Boot 發(fā)郵件,推薦看下。
例如這些由網(wǎng)易郵箱提供的錯(cuò)誤編碼標(biāo)識(shí):
421
421 HL:REP 該IP發(fā)送行為異常,存在接收者大量不存在情況,被臨時(shí)禁止連接。請(qǐng)檢查是否有用戶發(fā)送病毒或者垃圾郵件,并核對(duì)發(fā)送列表有效性;
421 HL:ICC 該IP同時(shí)并發(fā)連接數(shù)過大,超過了網(wǎng)易的限制,被臨時(shí)禁止連接。請(qǐng)檢查是否有用戶發(fā)送病毒或者垃圾郵件,并降低IP并發(fā)連接數(shù)量;
421 HL:IFC 該IP短期內(nèi)發(fā)送了大量信件,超過了網(wǎng)易的限制,被臨時(shí)禁止連接。請(qǐng)檢查是否有用戶發(fā)送病毒或者垃圾郵件,并降低發(fā)送頻率;
421 HL:MEP 該IP發(fā)送行為異常,存在大量偽造發(fā)送域域名行為,被臨時(shí)禁止連接。請(qǐng)檢查是否有用戶發(fā)送病毒或者垃圾郵件,并使用真實(shí)有效的域名發(fā)送;
450
450 MI:CEL 發(fā)送方出現(xiàn)過多的錯(cuò)誤指令。請(qǐng)檢查發(fā)信程序;
450 MI:DMC 當(dāng)前連接發(fā)送的郵件數(shù)量超出限制。請(qǐng)減少每次連接中投遞的郵件數(shù)量;
450 MI:CCL 發(fā)送方發(fā)送超出正常的指令數(shù)量。請(qǐng)檢查發(fā)信程序;
450 RP:DRC 當(dāng)前連接發(fā)送的收件人數(shù)量超出限制。請(qǐng)控制每次連接投遞的郵件數(shù)量;
450 RP:CCL 發(fā)送方發(fā)送超出正常的指令數(shù)量。請(qǐng)檢查發(fā)信程序;
450 DT:RBL 發(fā)信IP位于一個(gè)或多個(gè)RBL里。請(qǐng)參考http://www.rbls.org/關(guān)于RBL的相關(guān)信息;
450 WM:BLI 該IP不在網(wǎng)易允許的發(fā)送地址列表里;
450 WM:BLU 此用戶不在網(wǎng)易允許的發(fā)信用戶列表里;
451
451 DT:SPM ,please try again 郵件正文帶有垃圾郵件特征或發(fā)送環(huán)境缺乏規(guī)范性,被臨時(shí)拒收。請(qǐng)保持郵件隊(duì)列,兩分鐘后重投郵件。需調(diào)整郵件內(nèi)容或優(yōu)化發(fā)送環(huán)境;
451 Requested mail action not taken: too much fail authentication 登錄失敗次數(shù)過多,被臨時(shí)禁止登錄。請(qǐng)檢查密碼與帳號(hào)驗(yàn)證設(shè)置;
451 RP:CEL 發(fā)送方出現(xiàn)過多的錯(cuò)誤指令。請(qǐng)檢查發(fā)信程序;
451 MI:DMC 當(dāng)前連接發(fā)送的郵件數(shù)量超出限制。請(qǐng)控制每次連接中投遞的郵件數(shù)量;
451 MI:SFQ 發(fā)信人在15分鐘內(nèi)的發(fā)信數(shù)量超過限制,請(qǐng)控制發(fā)信頻率;
451 RP:QRC 發(fā)信方短期內(nèi)累計(jì)的收件人數(shù)量超過限制,該發(fā)件人被臨時(shí)禁止發(fā)信。請(qǐng)降低該用戶發(fā)信頻率;
451 Requested action aborted: local error in processing 系統(tǒng)暫時(shí)出現(xiàn)故障,請(qǐng)稍后再次嘗試發(fā)送;
500
500 Error: bad syntaxU
標(biāo)題名稱:SpringBoot發(fā)郵件和附件,超實(shí)用!
分享URL:http://www.fisionsoft.com.cn/article/ccehpsi.html


咨詢
建站咨詢
