文章目录
- Java发送邮箱的方式
- 1. 基于 Javax.mail 实现
- 关于附件上传的方法
- 2. 基于 org.apache.commons.mail 实现
- 常见报错
- 3. 基于 spring-boot-starter-mail 实现(推荐)
实际开发时需要实现邮件发送,本文章实现如何从零实现邮件发送。也就是 Spring Boot 项目中如何实现邮箱发送。
Java发送邮箱的方式
1、前提:需要获取发件人邮箱的授权码,也就是打开POP3/IMAP/SMTP服务设置,拿到授权码。
2、获取到邮件服务器的 smtp 地址:
| 服务商 | smtp服务地址 | smtp服务端口 | pop3服务地址 | pop3服务端口 |
|---|---|---|---|---|
| 新浪: sina.com | smtp.sina.com.cn | 25 | pop3.sina.com.cn | 110 |
| 搜狐:sohu.com | smtp.sohu.com | 25 | pop3.sohu.com | 110 |
| 163:163.com | smtp.163.com | 25 | smtp.163.com | 110 |
| QQ:qq.com | smtp.qq.com | 25 或 465 或 587 | smtp.qq.com | 110 |
| foxmail:foxmail.com | smtp.foxmail.com | 25 | pop3.foxmail.com | 110 |
| QQ企业邮箱:exmail.qq.com | smtp.exmail.qq.com | 995 | pop3.exmail.qq.com | 587/465 |
1. 基于 Javax.mail 实现
先引入依赖:
<dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version>
</dependency>
大致的流程:
1、创建配置项变量 Properties 对象,用于声明 smtp 相关配置;
2、创建一个Session,重写一个Authenticator,用于声明发件人邮箱地址和授权码;
3、利用 session 创建一个 MimeMessage 对象,再利用 MimeMessage 创建一个 MimeMessageHelper 对象,该对象用于设置收件人、发件人、抄送、秘密抄送、主题、内容、附件、发送时间等属性;
4、利用 Transport.send 方法发送邮件。
代码示例:
@Slf4j
public class EmailJavax {// 也可以从配置文件中取值// smtp服务地址private static final String senderSmtpHost = "smtp.qq.com";// 邮箱端口号private static final String senderSmtpPort = "465";// 发信人邮箱private static final String senderEmail = "xxx@qq.com";// 发信人邮箱授权码private static final String senderPassword = "xxx";/*** 邮件发送** @param subject 邮件主题* @param content 邮件内容* @param contentIsHtml 内容是否为html格式* @param fromMailPersonalName 发件人昵称* @param toMail 收件人邮箱* @param ccMail 抄送人邮箱* @param bccMail 秘密抄送人邮箱* @param fileNames 文件名(本地路径)*/public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, List<String> fileNames) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {// 1.创建配置项变量,用于声明 smtp 相关配置Properties properties = System.getProperties();// smtp服务地址properties.put("mail.smtp.host", senderSmtpHost);// smtp服务端口properties.put("mail.smtp.port", senderSmtpPort);// 开启验证properties.put("mail.smtp.auth", "true");// 开启TLS加密properties.put("mail.smtp.starttls.enable", "true");// 是否启用socketFactory,默认为trueproperties.put("mail.smtp.socketFactory.fallback", "true");MailSSLSocketFactory sf = new MailSSLSocketFactory();sf.setTrustAllHosts(true);properties.put("mail.smtp.ssl.enable", "true");properties.put("mail.smtp.ssl.socketFactory", sf);// 2.重写Authenticator,用于声明发件人邮箱地址和授权码// 建立会话,将邮箱授权码给jvmSession session = Session.getDefaultInstance(properties, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(senderEmail, senderPassword);}});// 设置为true可以在控制台打印发送过程,生产环境关闭session.setDebug(true);// 3.创建MimeMessage对象// 创建邮件对象MimeMessage message = new MimeMessage(session);// 创建MimeMessageHelper对象,通过MimeMessageHelper设置正文和附件,否则会导致两者显示不全MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");//设置发件人helper.setFrom(new InternetAddress(senderEmail, fromMailPersonalName));// 设置收件人,to为收件人,cc为抄送,bcc为密送if (StringUtils.isEmpty(toMail)) {log.error("邮件收件人为空");return;}helper.setTo(InternetAddress.parse(toMail, false));if (!StringUtils.isEmpty(ccMail)) {helper.setCc(InternetAddress.parse(ccMail, false));}if (!StringUtils.isEmpty(bccMail)) {helper.setBcc(InternetAddress.parse(bccMail, false));}// 设置邮件主题helper.setSubject(subject);//设置邮件正文内容helper.setText(content, contentIsHtml);//设置发送的日期helper.setSentDate(new Date());// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)if (!CollectionUtils.isEmpty(fileNames)) {for (String fileName : fileNames) {FileDataSource fileDataSource = new FileDataSource(fileName);helper.addAttachment(fileDataSource.getName(), fileDataSource);}}// 4.调用Transport的send方法去发送邮件Transport.send(message);}
}
// 测试:
public class Test(){public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {// excel表格的存放位置:String fileName = "/xx/xx/xx/供应商接口参数.xlsx";String html = "<h1>统计数据如下所示:</h1>" +"<table border=\"1\">\n" +" <tr>\n" +" <th>月度销售额</th>\n" +" <th>年度销售额</th>\n" +" </tr>\n" +" <tr>\n" +" <td>10000</td>\n" +" <td>2000000</td>\n" +" </tr>\n" +"</table>";// 调方法:EmailJavax.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Collections.singletonList(fileName));}
}
关于附件上传的方法
附件上传有多种方式,除了上面用到的 FileDataSource 形式添加附件外,还有 文件、输入流的方式添加:
addAttachment(String attachmentFilename, DataSource dataSource)addAttachment(String attachmentFilename, File file)addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)addAttachment(String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
2. 基于 org.apache.commons.mail 实现
commons 包中提供了 Email 抽象类,该类下实现了
HtmlEmail(用于HTML正文,附件邮件发送)ImageHtmlEmail(用于HTML图片正文,附件邮件发送)MultiPartEmail(用于附件邮件发送)SimpleEmail(用于简单邮件发送)
其继承关系如图所示:

1、引入依赖:
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-email</artifactId><version>1.5</version>
</dependency>
2、实现:
@Slf4j
public class EmailCommons {// 也可以从配置文件中取值// smtp服务地址private static final String senderSmtpHost = "smtp.qq.com";// 邮箱端口号private static final String senderSmtpPort = "465";// 发信人邮箱private static final String senderEmail = "xxx@qq.com";// 发信人邮箱授权码private static final String senderPassword = "xxx";/*** 邮件发送** @param subject 邮件主题* @param content 邮件内容* @param contentIsHtml 内容是否为html格式* @param fromMailPersonalName 发件人昵称* @param toMail 收件人邮箱* @param ccMail 抄送人邮箱* @param bccMail 秘密抄送人邮箱* @param fileList 附件 */public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, File[] fileList) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {// 1.创建HtmlEmail对象HtmlEmail email = new HtmlEmail();// smtp服务地址email.setHostName(senderSmtpHost);// smtp服务端口email.setSmtpPort("mail.smtp.port", senderSmtpPort);email.setCharset("utf-8");// 邮件验证email.setAuthentication(senderEmail,senderPassword);//设置发件人email.setFrom(senderEmail, fromMailPersonalName);// 设置收件人,to为收件人,cc为抄送,bcc为密送if (StringUtils.isEmpty(toMail)) {log.error("邮件收件人为空");return;}email.addTo(toMail);if (!StringUtils.isEmpty(ccMail)) {email.addCc(ccMail);}if (!StringUtils.isEmpty(bccMail)) {email.addBcc(bccMail);}// 设置邮件主题email.setSubject(subject);//设置邮件正文内容if(contentIsHtml){email.setHtmlMsg(content);}else{email.setMsg(content);}// 设置附件if(!ObjectUtils.isEmpty(fileList)){for (File file : fileList) {EmailAttachment emailAttachment = new EmailAttachment();emailAttachment.setName(MimeUtility.encodeText(file.getName()));emailAttachment.setPath(file.getPath());email.attach(emailAttachment);}}// 4.调用send方法去发送邮件email.send();}
}
3、测试:
public class Test(){public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {// excel表格的存放位置:String fileName = "/xx/xx/xx/供应商接口参数.xlsx";File file = new File(fileName);String html = "<h1>统计数据如下所示:</h1>" +"<table border=\"1\">\n" +" <tr>\n" +" <th>月度销售额</th>\n" +" <th>年度销售额</th>\n" +" </tr>\n" +" <tr>\n" +" <td>10000</td>\n" +" <td>2000000</td>\n" +" </tr>\n" +"</table>";EmailCommons.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null,new File[]{file} );}
}
常见报错
1、535 Login Fail. Please enter your authorization code to login
原因:邮箱验证设置的账号密码错误
解决:注意参数值正确性:email.setAuthentication(发件人邮箱地址,邮箱授权码);
2、MessagingException: Got bad greeting from SMTP host: smtp.qq.com, port: 465, response: [EOF]
解决:commons.mail 发送邮件时,QQ 邮箱使用默认端口 25 即可
3. 基于 spring-boot-starter-mail 实现(推荐)
1、引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2、使用配置文件:
spring:# 配置发送邮件的配置信息mail:# 配置smtp服务主机地址host: smtp.qq.com# 发送者邮箱username: XXX@qq.com# 配置密码,注意不是真正的密码,而是申请到的授权码password: jlpXXXXXdecj# 端口号:465或587port: 465# 默认的邮件编码为UTF-8default-encoding: UTF-8# 其他参数properties:mail:# 配置SSL 加密工厂smtp:ssl:# 本地测试,先放开sslenable: truerequired: true# 开启debug模式,这样邮件发送过程的日志会在控制台打印出来,方便排查错误debug: true
3、实现:
/*** 发送邮件类*/
public class SendEmailUtil {// 注入系统相关类@Autowiredprivate JavaMailSender javaMailSender;@Autowiredprivate MailProperties mailProperties;// 发送者邮箱
// @Value("${spring.mail.username}")
// private String sendMailer;/*** 邮件发送1** @param subject 邮件主题* @param content 邮件内容* @param contentIsHtml 内容是否为html格式* @param fromMailPersonalName 发件人昵称* @param toMail 收件人邮箱* @param ccMail 抄送人邮箱* @param bccMail 秘密抄送人邮箱* @param fileNames 文件名(本地文件名)*/public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,String toMail, String ccMail, String bccMail, List<String> fileNames) throws MessagingException, UnsupportedEncodingException {// true 代表支持复杂的类型MimeMessage mimeMessage = javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);/* 邮件发信人:两种写法:1. 定义成员变量获取application.yml的username属性@Value("${spring.mail.username}")private String sendMailer;helper.setFrom(sendMailer,发件人名称)2. 注入系统类的对象,然后调方法获取,获取的值也是application.yml文件中的值@Autowiredprivate MailProperties mailProperties;helper.setFrom(mailProperties.getUsername(),发件人名称);*/helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);// 邮件收信人 1或多个helper.setTo(toMail);if (!ObjectUtils.isEmpty(ccMail)) {// 邮件抄送人helper.setCc(ccMail);}if (!ObjectUtils.isEmpty(bccMail)) {// 邮件私密抄送人helper.setBcc(bccMail);}// 邮件主题helper.setSubject(subject);// 邮件内容 contentIsHtml值为 true 代表支持htmlhelper.setText(content, contentIsHtml);// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)if (!CollectionUtils.isEmpty(fileNames)) {for (String fileName : fileNames) {// 添加邮件附件FileDataSource fileDataSource = new FileDataSource(fileName);helper.addAttachment(fileDataSource.getName(), fileDataSource);}}// 发送邮件javaMailSender.send(mimeMessage);}/*** 邮件发送2 -- 方法优化 -- 文件对象** @param subject 邮件主题* @param content 邮件内容* @param contentIsHtml 内容是否为html格式* @param fromMailPersonalName 发件人昵称* @param toMail 收件人邮箱* @param ccMail 抄送人邮箱* @param bccMail 秘密抄送人邮箱* @param files 文件对象*/public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,String toMail, String ccMail, String bccMail, File[] files) throws MessagingException, UnsupportedEncodingException {MimeMessage message = javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);helper.setTo(toMail);if (!ObjectUtils.isEmpty(ccMail)) {helper.setCc(ccMail);}if (!ObjectUtils.isEmpty(bccMail)) {helper.setBcc(bccMail);}helper.setSubject(subject);helper.setText(content, contentIsHtml);// 设置附件,不能是远程文件if (!ObjectUtils.isEmpty(files)) {for (File file : files) {helper.addAttachment(file.getName(), file);}}javaMailSender.send(message);}/*** 邮件发送3 -- 方法优化 -- 使用流** @param subject 邮件主题* @param content 邮件内容* @param contentIsHtml 内容是否为html格式* @param fromMailPersonalName 发件人昵称* @param toMail 收件人邮箱* @param ccMail 抄送人邮箱* @param bccMail 秘密抄送人邮箱* @param fileName 文件名称* @param fileInput 文件流*/public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,String toMail, String ccMail, String bccMail, String fileName, InputStreamSource fileInput) throws MessagingException, UnsupportedEncodingException {MimeMessage message = javaMailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);helper.setTo(toMail);if (!ObjectUtils.isEmpty(ccMail)) {helper.setCc(ccMail);}if (!ObjectUtils.isEmpty(bccMail)) {helper.setBcc(bccMail);}helper.setSubject(subject);helper.setText(content, contentIsHtml);// 设置附件,不能是远程文件if (fileInput != null) {helper.addAttachment(fileName, fileInput);}javaMailSender.send(message);}
}
关于邮件发送的方法参数: 上面几个方法,最后接收附件的参数都不一样,说明可以灵活变化
sendEmail(xxx, List<String> fileNames):可以接收多个附件,其中传的时候,就是附件的绝对路径sendEmail(xxx, File[] files):可以接收多个附件,传的时候,就是附件的文件对象sendEmail(xxx, InputStreamSource fileInput):接收一个附件,传的时候,就是附件的流
5、测试:
/*** excel表格生成工具*/
public class ExcelUtil {/*** 生成excel文件** @param fileName excel文件路径* @param dataList 数据列表* @param clazz 导出对象类* @param <T>* @return*/public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) {// 生成文件File file = new File(fileName);// 单sheet写入EasyExcel.write(file, clazz).sheet("XXX").doWrite(dataList);return file;}/*** 生成excel文件 -- 方法优化 -- 用流** @param dataList 数据列表* @param clazz 导出对象类* @param <T>* @return*/public static <T> ByteArrayOutputStream generateExcel(List<T> dataList, Class<T> clazz) {ByteArrayOutputStream out = new ByteArrayOutputStream();// 单excel写入EasyExcel.write(out, clazz).sheet("XXX").doWrite(dataList);return out;}}
public class Test(){public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {String content = "客户统计数据如附件所示";// 测试邮件发送1// excel表格的存放位置:String fileName = "/xx/xx/xx/供应商接口参数.xlsx";String html = "<h1>统计数据如下所示:</h1>" +"<table border=\"1\">\n" +" <tr>\n" +" <th>月度销售额</th>\n" +" <th>年度销售额</th>\n" +" </tr>\n" +" <tr>\n" +" <td>10000</td>\n" +" <td>2000000</td>\n" +" </tr>\n" +"</table>";SendEmailUtil.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Arrays.asList(fileName));// 测试邮件发送2File excel = ExcelUtil.generateExcel("文件名", 表格映射的实体类对象, 表格映射的实体类.class);SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, new File[]{excel});// 测试邮件发送3ByteArrayOutputStream bos = ExcelUtil.generateExcel(userInfos, UserInfo.class);SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, fileName, new ByteArrayResource(bos.toByteArray()));}
}
注意: 实现 excel 生成,然后发送邮箱 的代码,可以查看这篇文章:生成 excel 并发送邮箱
至此!文章的内容结束!!记得关注收藏,有更多精彩内容!!!
