• 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("xxx@163.com");
    26         mail.setPort("25");
    27         mail.setUserName("xxx@163.com");
    28         mail.setPassword("xxxxx");
    29         //设置收件人
    30         List<String> receiver = new ArrayList<String>();
    31         receiver.add("xxx@qq.com");
    32      //设置抄送人
    33         List<String> copier = new ArrayList<String>();
    34         copier.add("xxx@163.com");
    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 ### u8F93u51FAu5230u63A7u5236u53F0 ###
     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 ## u8F93u51FAu5230u65E5u5FD7u6587u4EF6 ###
    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 ## u4FDDu5B58u5F02u5E38u4FE1u606Fu5230u5355u72ECu6587u4EF6 ###
    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 ## u4FDDu5B58u5F02u5E38u4FE1u606Fu5230u5355u72ECu6587u4EF6 ###
    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

    测试结果:

    邮件实际收到的内容:

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

    附:项目结构图

  • 相关阅读:
    Ubuntu下安装 jdk6
    开发内容分解的9个角度
    2020年,为什么我们应该使用abapGit代替SAPLink
    如何禁用IntelliJ IDEA的LightEdit模式
    通过AMDP调用HANA的PAL函数
    用Python开发的Wox股票插件
    概念验证:在Kubernetes中部署ABAP
    使用ABAP Data Validator验证数据有效性
    开源工具abaplint的介绍
    【被面试官吊打】从系统角度考虑性能优化
  • 原文地址:https://www.cnblogs.com/hafiz/p/5526833.html
Copyright © 2020-2023  润新知