Java发送邮件初窥

一、背景

  最近朋友的公司有用到这个功能,之前对这一块也不是很熟悉,就和他一起解决出现的异常的同时,也初窥一下使用Apache Common Email组件进行邮件发送。

二、Java发送邮件的注意事项

  1.不同的邮箱有不同的支持协议,比如有些只支持SSL协议,有些只支持TLS协议,还有些同时支持SSL和TLS协议。

  2.支持不同协议的邮箱,在使用Java发送邮件时要使用不同的方式发送,下面我会介绍基于SSL和TLS的两种实现方式。

  附:常用邮箱的服务器(Smtp/POP3)地址和端口总结

三、代码实现

说明:本例采用Apache Common Email组件进行开发。

1.发送邮件实体类

 1 package com.hafiz.zhang.mail.entity;
 2
 3 import java.io.Serializable;
 4 import java.util.List;
 5
 6 import org.apache.commons.mail.EmailAttachment;
 7
 8 /**
 9  * @author hafiz.Zhang
10  * @Date 2016年5月23日 下午2:40:36
11  * @Description 邮件实体类
12  */
13 public class MailEntity implements Serializable{
14     private static final long serialVersionUID = 1589570366044890462L;
15     public static final String ENCODING = "UTF-8";    //邮件编码
16     private String host;                             //服务器地址
17     private String port;                              //发送端口
18     private String sender;                            //发件人邮箱
19     private List<String> receiver;                    //收件人邮箱
20     private List<String> copier;                      //抄送人
21     private String senderName;                        //发件人昵称
22     private String userName;                          //发件邮箱账号
23     private String password;                          //发件邮箱密码
24     private String subject;                           //邮件主题
25     private String content;                           //邮件内容(支持HTML)
26     private List<EmailAttachment> attachments;        //邮件附件
27     public String getHost() {
28         return host;
29     }
30     public void setHost(String host) {
31         this.host = host;
32     }
33     public String getPort() {
34         return port;
35     }
36     public void setPort(String port) {
37         this.port = port;
38     }
39     public String getSender() {
40         return sender;
41     }
42     public void setSender(String sender) {
43         this.sender = sender;
44     }
45     public List<String> getReceiver() {
46         return receiver;
47     }
48     public void setReceiver(List<String> receiver) {
49         this.receiver = receiver;
50     }
51     public List<String> getCopier() {
52         return copier;
53     }
54     public void setCopier(List<String> copier) {
55         this.copier = copier;
56     }
57     public String getSenderName() {
58         return senderName;
59     }
60     public void setSenderName(String senderName) {
61         this.senderName = senderName;
62     }
63     public String getUserName() {
64         return userName;
65     }
66     public void setUserName(String userName) {
67         this.userName = userName;
68     }
69     public String getPassword() {
70         return password;
71     }
72     public void setPassword(String password) {
73         this.password = password;
74     }
75     public String getSubject() {
76         return subject;
77     }
78     public void setSubject(String subject) {
79         this.subject = subject;
80     }
81     public String getContent() {
82         return content;
83     }
84     public void setContent(String content) {
85         this.content = content;
86     }
87     public List<EmailAttachment> getAttachments() {
88         return attachments;
89     }
90     public void setAttachments(List<EmailAttachment> attachments) {
91         this.attachments = attachments;
92     }
93     @Override
94     public String toString() {
95         return "MailEntity [host=" + host + ", port=" + port + ", sender=" + sender + ", receiver=" + receiver
96                 + ", copier=" + copier + ", senderName=" + senderName + ", userName=" + userName + ", password="
97                 + password + ", subject=" + subject + ", content=" + content + ", attachments=" + attachments + "]";
98     }
99 }

注:实体类代码比较臃肿,建议使用lombok进行简化,lombok的使用方式见我的另一篇博客:Java简化代码神器-Lombok

2.发送邮件支持协议列举类

 1 package com.hafiz.zhang.mail.tools.factory;
 2
 3 /**
 4  * @author hafiz.Zhang
 5  * @Date 2016年5月25日 下午12:08:59
 6  * @Description 列举发送邮件的可用协议
 7  */
 8 public class Protocols {
 9     //SSL协议
10     public static String SSL_MAIL_UTIL = "com.hafiz.zhang.mail.tools.SSLMailUtil";
11     //TLS协议
12     public static String TLS_MAIL_UTIL = "com.hafiz.zhang.mail.tools.TLSMailUtil";
13 }

3.发送邮件工具接口类

 1 package com.hafiz.zhang.mail.tools;
 2
 3 import com.hafiz.zhang.mail.entity.MailEntity;
 4
 5 /**
 6  * @author hafiz.Zhang
 7  * @Date 2016年5月23日 下午3:26:15
 8  * @Description 邮件发送接口类
 9  */
10 public interface IMailUtil {
11     /**
12      * @Author hafiz.Zhang
13      * @Description:  发送邮件
14      * @param    mail要发送邮件的实体类
15      * @return Boolean   发送结果
16      */
17     public abstract Boolean send(MailEntity mail);
18 }

4.基于SSL协议发送邮件工具实现类

 1 package com.hafiz.zhang.mail.tools;
 2
 3 import java.util.List;
 4
 5 import org.apache.commons.mail.EmailAttachment;
 6 import org.apache.commons.mail.EmailException;
 7 import org.apache.commons.mail.HtmlEmail;
 8 import org.slf4j.Logger;
 9 import org.slf4j.LoggerFactory;
10
11 import com.hafiz.zhang.mail.entity.MailEntity;
12
13 /**
14  * @author hafiz.Zhang
15  * @Date 2016年5月23日 下午3:09:13
16  * @Description 通过SSL方式发送邮件工具类
17  */
18 public class SSLMailUtil implements IMailUtil{
19     private static Logger log = LoggerFactory.getLogger(SSLMailUtil.class);
20
21     public Boolean send(MailEntity mail) {
22         // 创建待发送的emil对象
23         HtmlEmail email = new HtmlEmail();
24         try {
25
26             // 设置SMTP发送服务器的名字:163的如下:"smtp.163.com"
27             email.setHostName(mail.getHost());
28             //设置端口号
29             if(null != mail.getPort()) {
30                 email.setSmtpPort(Integer.parseInt(mail.getPort()));
31             }
32             // 设置邮件字符编码集
33             email.setCharset(MailEntity.ENCODING);
34             // 设置抄送人
35             email.addCc(mail.getCopier().toArray(new String[mail.getCopier().size()]));
36             // 设置发送人的邮箱
37             email.setFrom(mail.getSender(), mail.getSenderName());
38             // 收件人的邮箱
39             email.addTo(mail.getReceiver().toArray(new String[mail.getReceiver().size()]));
40             // 如果需要认证信息的话,设置认证:用户名-密码。分别为发件人在邮件服务器上的注册名称和密码
41             email.setAuthentication(mail.getUserName(), mail.getPassword());
42             // 设置要发送的邮件主题
43             email.setSubject(mail.getSubject());
44             // 设置要发送的信息,由于使用了HtmlEmail,可以在邮件内容中使用HTML标签
45             email.setMsg(mail.getContent());
46             // 设置附件
47             List<EmailAttachment> attachments = mail.getAttachments();
48             if(null != attachments && attachments.size() > 0) {
49                 for(EmailAttachment attachment : attachments) {
50                     email.attach(attachment);
51                 }
52             }
53             // 发送
54             email.send();
55
56             log.info(mail.getSender() + " 发送邮箱到 " + mail.getReceiver());
57
58             return true;
59         } catch (EmailException e) {
60             log.error(mail.getSender() + " 发送邮箱到 " + mail.getReceiver() + " 失败,错误原因:" + e.getMessage());
61             e.printStackTrace();
62         }
63         return false;
64     }
65 }

5.基于TLS协议的发送邮件实现类

 1 package com.hafiz.zhang.mail.tools;
 2
 3 import java.util.List;
 4 import java.util.Properties;
 5
 6 import javax.mail.Session;
 7
 8 import org.apache.commons.mail.DefaultAuthenticator;
 9 import org.apache.commons.mail.EmailAttachment;
10 import org.apache.commons.mail.EmailException;
11 import org.apache.commons.mail.HtmlEmail;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 import com.hafiz.zhang.mail.entity.MailEntity;
16
17 /**
18  * @author hafiz.Zhang
19  * @Date 2016年5月23日 下午3:23:15
20  * @Description 通过TLS协议发送邮件工具类
21  */
22 public class TLSMailUtil implements IMailUtil{
23     private static Logger log = LoggerFactory.getLogger(TLSMailUtil.class);
24
25     public Boolean send(MailEntity mail){
26         HtmlEmail email = new HtmlEmail();
27         try {
28             Properties prop = new Properties();
29             // 设置SMTP发送服务器的名字:163的如下:"smtp.163.com"
30             prop.setProperty("mail.smtp.host", mail.getHost());
31             // 设置SMTP发送服务器的端口
32             prop.setProperty("mail.smtp.port", mail.getPort());
33             // 设置是否需要认证
34             prop.setProperty("mail.smtp.auth", "true");
35             // 开启TLS加密方式
36             prop.setProperty("mail.smtp.starttls.enable", "true");
37             // 添加信任的服务器
38             prop.setProperty("mail.smtp.ssl.trust", mail.getHost());
39             // 进行认证并获取需要的session
40             DefaultAuthenticator defaultAuthenticator =
41                     new DefaultAuthenticator(mail.getUserName(), mail.getPassword());
42             Session session = Session.getInstance(prop,defaultAuthenticator);
43             email.setMailSession(session);
44             // 设置字符编码集
45             email.setCharset(MailEntity.ENCODING);
46             // 设置发送人的邮箱
47             email.setFrom(mail.getSender(), mail.getSenderName());
48             // 设置收件人的邮箱
49             email.addTo(mail.getReceiver().toArray(new String[mail.getReceiver().size()]));
50             // 设置抄送人
51             email.addCc(mail.getCopier().toArray(new String[mail.getCopier().size()]));
52             // 设置要发送的邮件主题
53             email.setSubject(mail.getSubject());
54             // 设置要发送的信息,由于使用了HtmlEmail,可以在邮件内容中使用HTML标签
55             email.setMsg(mail.getContent());
56             // 设置附件
57             List<EmailAttachment> attachments = mail.getAttachments();
58             if(null != attachments && attachments.size() > 0) {
59                 for(EmailAttachment attachment : attachments) {
60                     email.attach(attachment);
61                 }
62             }
63             // 发送
64             email.send();
65             log.info(mail.getSender() + " 发送邮箱到 " + mail.getReceiver());
66             return true;
67         } catch (EmailException e) {
68             log.error(mail.getSender() + " 发送邮箱到 " + mail.getReceiver() + " 失败,错误原因:" + e.getMessage());
69             e.printStackTrace();
70         }
71         return false;
72     }
73 }

注意:

  1.如果没有设置开启TLS加密方式的代码(上面代码中标红处),则会出现Caused by: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM异常,异常图片如下:

  2.如果没有设置添加信任的主机服务器的代码(上面代码中标红处),则会出现:Caused by: javax.mail.MessagingException: Could not convert socket to TLS;异常,异常图片如下:

6.获取邮件发送类的工厂类

 1 package com.hafiz.zhang.mail.tools.factory;
 2
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5
 6 import com.hafiz.zhang.mail.tools.IMailUtil;
 7
 8 /**
 9  * @author hafiz.Zhang
10  * @Date 2016年5月23日 下午3:43:15
11  * @Description 获取邮件发送类的工厂类
12  */
13 public class MailUtilsFactory {
14     private static Logger logger = LoggerFactory.getLogger(MailUtilsFactory.class);
15
16     private MailUtilsFactory() {
17         super();
18     }
19
20     public static IMailUtil getMailUtil(String name) {
21         IMailUtil mailUtil = null;
22         try {
23             mailUtil = (IMailUtil)Class.forName(name).newInstance();
24         } catch (Exception e) {
25             logger.error("获取邮件发送类失败,失败原因:" + e.getMessage());
26             e.printStackTrace();
27         }
28         return mailUtil;
29     }
30 }

7.测试类

 1 package com.hafiz.zhang.mail.test;
 2
 3 import java.net.MalformedURLException;
 4 import java.net.URL;
 5 import java.util.ArrayList;
 6 import java.util.List;
 7
 8 import org.apache.commons.mail.Email;
 9 import org.apache.commons.mail.EmailAttachment;
10
11 import com.hafiz.zhang.mail.entity.MailEntity;
12 import com.hafiz.zhang.mail.tools.IMailUtil;
13 import com.hafiz.zhang.mail.tools.factory.MailUtilsFactory;
14 import com.hafiz.zhang.mail.tools.factory.Protocols;
15
16 /**
17  * @author hafiz.Zhang
18  * @Date 2016年5月23日 下午3:39:52
19  * @Description 两种方式发送邮件的测试类
20  */
21 public class TestMailSender {
22     public static void main(String[] args) throws MalformedURLException {
23         MailEntity mail = new MailEntity();
24         mail.setHost("smtp.163.com");
25         mail.setSender("[email protected]");
26         mail.setPort("25");
27         mail.setUserName("[email protected]");
28         mail.setPassword("xxxxx");
29         //设置收件人
30         List<String> receiver = new ArrayList<String>();
31         receiver.add("[email protected]");
32      //设置抄送人
33         List<String> copier = new ArrayList<String>();
34         copier.add("[email protected]");
35
36         List<EmailAttachment> attachments = new ArrayList<EmailAttachment>();
37         // 添加本地附件
38         EmailAttachment att = new EmailAttachment();
39         att.setDescription("这是附件图片");
40         att.setDisposition(EmailAttachment.ATTACHMENT);
41         att.setName("好看的图片.png");
42         att.setPath("C:\\Users\\ZHF\\Desktop\\333.png");
43         attachments.add(att);
44         // 添加网络附件
45         EmailAttachment att2 = new EmailAttachment();
46         att2.setDescription("这是网络附件");
47         att2.setDisposition(EmailAttachment.ATTACHMENT);
48         att2.setName("网络附件.jpg");
49         att2.setURL(new URL("http://7xpsw5.com1.z0.glb.clouddn.com/41a9ccf2-2a22-44bd-aa3b-8e8779db1caf.jpg"));
50         attachments.add(att2);
51
52         mail.setAttachments(attachments);
53         mail.setCopier(copier);
54         mail.setReceiver(receiver);
55         mail.setSubject("测试邮件发送主题");
56      // String string = "<html><head></head><body><div>测试Java发送邮件内容</div></body></html>";
57         String string = "测试Java发送邮件内容";
58         mail.setContent(string);
59         // IMailUtil mailUtil = MailUtilsFactory.getMailUtil(Protocols.SSL_MAIL_UTIL);
60         IMailUtil mailUtil = MailUtilsFactory.getMailUtil(Protocols.TLS_MAIL_UTIL);
61         mailUtil.send(mail);
62         System.out.println("邮件发送成功");
63     }
64 }

8.工程pom.xml文件(由于本例使用maven工程)

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 3   <modelVersion>4.0.0</modelVersion>
 4
 5   <groupId>com.hafiz.zhang</groupId>
 6   <artifactId>sendEmail</artifactId>
 7   <version>0.0.1-SNAPSHOT</version>
 8   <packaging>jar</packaging>
 9
10   <name>sendEmail</name>
11   <url>http://maven.apache.org</url>
12
13   <properties>
14     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15   </properties>
16
17   <dependencies>
18      <dependency>
19          <groupId>org.apache.commons</groupId>
20          <artifactId>commons-email</artifactId>
21          <version>1.4</version>
22      </dependency>
23      <dependency>
24         <groupId>org.slf4j</groupId>
25         <artifactId>slf4j-log4j12</artifactId>
26         <version>1.6.4</version>
27      </dependency>
28      <dependency>
29         <groupId>org.slf4j</groupId>
30         <artifactId>slf4j-api</artifactId>
31         <version>1.6.4</version>
32      </dependency>
33      <dependency>
34          <groupId>log4j</groupId>
35          <artifactId>log4j</artifactId>
36          <version>1.2.16</version>
37      </dependency>
38      <dependency>
39          <groupId>junit</groupId>
40          <artifactId>junit</artifactId>
41          <version>4.12</version>
42      </dependency>
43   </dependencies>
44 </project>

至于,本文为何采用slf4j而不是直接采用log4j进行日志控制输出,详见另一篇博客:slf4j介绍以及实现原理窥探

9.日志输出格式文件

 1 ### set log levels ###
 2 log4j.rootLogger = DEBUG ,  stdout , D , E , F
 3
 4 ### \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ###
 5 log4j.appender.stdout = org.apache.log4j.ConsoleAppender
 6 log4j.appender.stdout.Target = System.out
 7 log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
 8 log4j.appender.stdout.layout.ConversionPattern =  %-d{yyyy-MM-dd HH:mm:ss} [ %p ] [ %l-%t:%r ] %m%n
 9
10 ## \u8F93\u51FA\u5230\u65E5\u5FD7\u6587\u4EF6 ###
11 log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
12 log4j.appender.D.DatePattern = ‘.‘yyyyMMdd
13 log4j.appender.D.File = logs/api/warn.log
14 log4j.appender.D.Append = true
15 log4j.appender.D.Threshold = WARN
16 log4j.appender.D.layout = org.apache.log4j.PatternLayout
17 log4j.appender.D.encoding=UTF-8
18 log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %p ] [ %l-%t:%r ] %m%n
19
20 ## \u4FDD\u5B58\u5F02\u5E38\u4FE1\u606F\u5230\u5355\u72EC\u6587\u4EF6 ###
21 log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
22 log4j.appender.E.File = logs/api/error.log
23 log4j.appender.E.DatePattern = ‘.‘yyyyMMdd
24 log4j.appender.E.Append = true
25 log4j.appender.E.Threshold = ERROR
26 log4j.appender.E.layout = org.apache.log4j.PatternLayout
27 log4j.appender.E.encoding=UTF-8
28 log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %p ] [ %l-%t:%r ] %m%n
29
30 ## \u4FDD\u5B58\u5F02\u5E38\u4FE1\u606F\u5230\u5355\u72EC\u6587\u4EF6 ###
31 log4j.appender.F = org.apache.log4j.DailyRollingFileAppender
32 log4j.appender.F.File = logs/api/debug.log
33 log4j.appender.F.DatePattern = ‘.‘yyyyMMdd
34 log4j.appender.F.Append = true
35 log4j.appender.F.Threshold = DEBUG
36 log4j.appender.F.layout = org.apache.log4j.PatternLayout
37 log4j.appender.F.encoding=UTF-8
38 log4j.appender.F.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %p ] [ %l-%t:%r ] %m%n

测试结果:

邮件实际收到的内容:

为了保证以后的兼容性,本例采用了工厂设计模式,有什么不正确的或需要改进的,请各位批评指导,谢谢!

附:项目结构图

时间: 2024-10-13 09:12:03

Java发送邮件初窥的相关文章

初窥ElasticSearch

初窥ElasticSearch 官网上面的,不知道讲的是什么.. youtube上面有一个start with,内容是在windows下面跑这个elastic search,然后用一个fidler工具可视化测试 https://www.youtube.com/watch?v=60UsHHsKyN4 粗略看起来,其实es和其他db没什么大区别,只是在搜索上有很多强大功能,所以很适合用在需要搜索的项目.貌似用curl发送一个JSON格式的数据(实际上是命令)到es就可以做CRUD elasticse

玩转oo对象模型(1) 之 初窥c++对象模型

============================================== copyright: KIRA-lzn ============================================== 转载请注明出处,这篇是我原创,翻版必究! ============================================== 第二篇,如果写的好,请点个赞呦.当然有不对之处,非常欢迎拍砖!!!! 自我介绍: USTC研一学生,目前在intel实习,研发岗 第二篇

Hadoop学习笔记(9) ——源码初窥

Hadoop学习笔记(9) ——源码初窥 之前我们把Hadoop算是入了门,下载的源码,写了HelloWorld,简要分析了其编程要点,然后也编了个较复杂的示例.接下来其实就有两条路可走了,一条是继续深入研究其编程及部署等,让其功能使用的淋漓尽致.二是停下来,先看看其源码,研究下如何实现的.在这里我就选择第二条路. 研究源码,那我们就来先看一下整个目录里有点啥: 这个是刚下完代码后,目录列表中的内容. 目录/文件 说明 bin 下面存放着可执行的sh命名,所有操作都在这里 conf 配置文件所在

初窥AspectJ

AspectJ可以说是Java中当之无愧的黑魔法.说它是黑魔法,一方面是因为它很强大,能够解决一些传统编程方法论解决不了的问题,而另一方面,它也相当的晦涩,有着比较陡峭的学习曲线. 本文将带大家探索下AspectJ是什么,能做什么,以及如何来做,希望通过本文能够让大家初窥AspectJ之门道 AOP是什么 相信很多人第一次听说AOP是在学习spring的时候,笔者也是.这个概念其实困扰了我很久,到底是AOP?AOP是Aspect Oriented Programming的缩写,和OOP(Obje

Scrapy 1.4 文档 01 初窥 Scrapy

初窥 Scrapy Scrapy 是用于抓取网站并提取结构化数据的应用程序框架,其应用非常广泛,如数据挖掘,信息处理或历史存档. 尽管 Scrapy 最初设计用于网络数据采集(web scraping),但它也可用于使用 API(如 Amazon Associates Web Services)提取数据或用作通用的网络爬虫. 爬虫(spider)示例 为了向您展示 Scrapy 带给您的是什么,我们将使用最简单的方式运行一个爬虫,向您展示一个 Scrape Spider 的例子. 这是一个爬虫的

jQuery源码学习(2):选择器初窥

选择器初窥 代码架构: jQuery选择器可以依照传入数据的类型分为五大类: 传入字符串:$("div"), $("#id"), $(".div1"),$(".div p.title") 传入html代码:$("<div></div>"), $("<div>1</div><div>2</div>") 传入对象:$(d

Boost.ASIO简要分析-1 初窥

Boost.Asio是一个主要用于网络及底层I/O编程的跨平台C++库. 1. 初窥 Boost.Asio支持对I/O对象进行同步及异步操作. 1.1 同步操作 同步操作的事件顺序如下图所示: 1) 调用者调用I/O对象的connect函数开始连接操作,socket.connect(server_endpoint): 2) I/O对象将连接请求传递给io_service: 3) io_service调用操作系统函数: 4) 操作系统返回结果给io_service: 5) io_service将结

Swift初窥----深入Swift

存储函数 内存中的Fibonacci函数,避免重复递归,来提高代码执行效率 模板 编译器 Swift编译器,使其可以编译出更快的机器代码 Swift初窥----深入Swift,布布扣,bubuko.com

初窥netfilter/iptables

做这个东西太麻烦了,一不小心,就被自己关门外了. ---------------------------------------------- 一.前言 二.环境 三.语法解析 四.配置及测试 1.SNAT案例 2.DNAT案例 3.SSH案例 4.SSH深入案例(自定义规则) 5.web和ftp(自定义规则) 6.web和ftp(系统默认规则) 五.保存 ---------------------------------------------- 一.前言 iptables即Linux 内核集