Java的邮件发送功能

简述

使用spring 的邮件发送功能,能够很简易地实现 配置自己的邮箱信息,发送邮件到指定人,包括抄送、密送、以及上传附件

pom.xml依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

由于版本兼容问题,使用过两种方式,都提供给大家;具体哪个版本兼容哪种方式,在此就不过多细究;


邮件信息实体封装

package com.kellan.demo.utils.entitys;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;

/**
 * 邮件信息 实体
 * @author: Kellan
 * @time: 2020/11/27 18:27
 */
@Data
public class MailVo {

    public MailVo() {
    }

    public MailVo(String from, String to, String subject, Date sentDate) {
        this.from = from;
        this.to = to;
        this.subject = subject;
        this.sentDate = sentDate;
    }

    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;
    /**
     * 邮件附件
     */
    @JsonIgnore
    private List<File> fileList;

}

方式一:(较新的版本: 在此使用的是 spring-boot 2.1.3)

package com.kellan.demo.utils.email;

import com.kellan.demo.utils.entitys.MailVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 发送邮箱工具类
 *
 * 使用该类,需要pom.xml引用 spring-boot-starter-mail
 * 并且在配置文件中,配置
 * spring.mail.host \ username \ password(授权码)
 *
 * @author: Kellan
 * @time: 2020/11/26 15:19
 */
@Slf4j
@Component
public class EmailUtils {

    @Resource
    JavaMailSenderImpl mailSender;

    public void sendMimeMail(MailVo mailVo) {
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage(), true);
            // 邮件发信人
            messageHelper.setFrom(mailVo.getFrom());
            // 收信人
            messageHelper.setTo(mailVo.getTo().split(","));
            // 主题
            messageHelper.setSubject(mailVo.getSubject());
            // 抄送
            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()) {
                    if("".equals(multipartFile.getOriginalFilename())){
                        break;
                    }
                    messageHelper.addAttachment(multipartFile.getOriginalFilename(), multipartFile);
                }
            }
            // 发送时间
            if (StringUtils.isEmpty(mailVo.getSentDate())) {
                mailVo.setSentDate(new Date());
                messageHelper.setSentDate(mailVo.getSentDate());
            }

            messageHelper.setText(mailVo.getText(),true);
            // 发送
            mailSender.send(messageHelper.getMimeMessage());
            mailVo.setStatus("ok");
            log.info("发送邮件成功:{}->{}", mailVo.getFrom(), mailVo.getTo());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}

方式二:(较新的版本: 在此使用的是 spring-boot 1.5.4)

package com.kellan.demo.utils.email;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Date;
import java.util.Properties;

/**
 * 发送邮箱工具类
 *
 * 使用该类,需要pom.xml引用 spring-boot-starter-mail
 *
 * @author: Kellan
 * @time: 2020/11/26 15:19
 */
@Component
public class EmailUtils {

    private final static Logger logger = LoggerFactory.getLogger(EmailUtils.class);


    private Session getSession() {
        // 获取系统属性
        Properties properties = System.getProperties();
        // 设置邮件服务器
        properties.setProperty("mail.smtp.host", "smtphz.qiye.163.com");

        properties.put("mail.smtp.auth", "true");

        Session session = Session.getDefaultInstance(properties, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("***@163.com", "Passw0rd"); //发件人邮件用户名、生成的授权码
            }
        });
        return session;
    }

    /**
     * 发送邮件
     * @param mailVo
     * @author: Kellan
     * @time: 2020/11/27 9:09
     */
    public boolean sendMimeMail(MailVo mailVo) {
        try {
            MimeMessage messageHelper = new MimeMessage(getSession());
            // 邮件发信人
            messageHelper.setFrom(mailVo.getFrom());
            // 收信人
            if (!StringUtils.isEmpty(mailVo.getTo())) {
                String[] split = mailVo.getTo().split(",");
                for (int i = 0; i < split.length; i++) {
                    messageHelper.addRecipient(Message.RecipientType.TO, new InternetAddress(split[i]));
                }
            }
            // 主题
            messageHelper.setSubject(mailVo.getSubject());
            // 发送时间
            if (StringUtils.isEmpty(mailVo.getSentDate())) {
                mailVo.setSentDate(new Date());
                messageHelper.setSentDate(mailVo.getSentDate());
            }
            // 抄送
            if (!StringUtils.isEmpty(mailVo.getCc())) {
                String[] split = mailVo.getCc().split(",");
                for (int i = 0; i < split.length; i++) {
                    messageHelper.addRecipient(Message.RecipientType.CC, new InternetAddress(split[i]));
                }
            }
            // 发送
            Transport.send(setMultipart(messageHelper, mailVo));
        } catch (Exception e) {
            logger.error("=== 发送邮件失败", e);
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 封装邮件 正文内容
     * @author: Kellan
     * @time: 2020/11/27 9:10
     */
    private MimeMessage setMultipart(MimeMessage message, MailVo mailVo) throws Exception{
        //设置邮件内容,混合模式
        MimeMultipart msgMultipart = new MimeMultipart("mixed");
        message.setContent(msgMultipart);
        //设置消息正文
        MimeBodyPart content = new MimeBodyPart();
        msgMultipart.addBodyPart(content);
        //设置正文格式
        MimeMultipart bodyMultipart = new MimeMultipart("related");
        content.setContent(bodyMultipart);
        //设置正文内容
        MimeBodyPart textPart = new MimeBodyPart();
        bodyMultipart.addBodyPart(textPart);
        textPart.setContent(mailVo.getText(), "text/plain;charset=UTF-8");

        // 设置附件
        if (!mailVo.getFileList().isEmpty()) {
            mailVo.getFileList().stream().forEach(file -> {
                //设置相关文件
                try {
                    MimeBodyPart filePart = new MimeBodyPart();
                    FileDataSource dataSource = new FileDataSource(file);
                    DataHandler dataHandler = new DataHandler(dataSource);
                    // 文件处理
                    filePart.setDataHandler(dataHandler);
                    // 附件名称
                    filePart.setFileName(file.getName());
                    // 放入正文(有先后顺序,所以在正文后面)
                    msgMultipart.addBodyPart(filePart);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        //保存文件准备发送
        message.saveChanges();
        return message;
    }
}

两种方式的区别

从代码的复杂程度来看,方式一是较为简易的;特别是在设置发送人、收件人,和附件上;代码的封装成都较高;而方式二在代码上虽然较为复杂,但是自主性较高,在消息体中,可自定义的样式比较倾向于程序员,可选择纯文本、html等样式;

使用Java发送邮件,最大的问题点在于开始配置时,经常报 验证失败;当时我也是在2.1.3版本中使用方式一验证可行后,回到项目的1.5.4版本中时,却始终验证不上; 后来迫于无奈,才用的方式二;


PS :

1、163邮箱必须使用授权码,且一个ip用一个授权码;(本地环境、测试环境、正式环境都需要不同的授权码)

2、阿里云服务器,发送邮件的端口25 默认是禁止的;然后遇到报错

com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtphz.qiye.163.com, 25; timeout -1
        at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2118)
        at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:712)
        at javax.mail.Service.connect(Service.java:388)
        at javax.mail.Service.connect(Service.java:246)
        at javax.mail.Service.connect(Service.java:195)
        at javax.mail.Transport.send0(Transport.java:254)
        at javax.mail.Transport.send(Transport.java:124)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
        at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
        at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

解决方式一:向阿里云申请开放25端口,申请方式 https://help.aliyun.com/knowledge_detail/56130.html

解决方式二:改用465端口

private Session getSession() {
    // 获取系统属性
    Properties properties = System.getProperties();
    // 设置邮件服务器
    properties.setProperty("mail.smtp.host", "smtphz.qiye.163.com");
    properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    properties.setProperty("mail.smtp.socketFactory.port", "465");
    properties.setProperty("mail.smtp.port", "465");

    properties.put("mail.smtp.auth", "true");

    Session session = Session.getDefaultInstance(properties, new Authenticator() {
        public PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(USER_NAME_CMP, PASSWORD_CMP); //发件人邮件用户名、生成的授权码
        }
    });
    return session;
}
package com.lccert.crm.chemistry.util; import java.util.Date; import java.util.Properties; import javax.mail.Message; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; public class SendMail { private static SendMail instance = null; private SendMail() { } public static SendMail getInstance() { if (instance == null) { instance = new SendMail(); } return instance; } public void send() { try { String to[]={"tiwsonchen@163.com","tiwson@163.com"}; Properties p = new Properties(); //Properties p = System.getProperties(); p.put("mail.smtp.auth", "true"); p.put("mail.transport.protocol", "smtp"); p.put("mail.smtp.host", "smtp.163.com"); p.put("mail.smtp.port", "25"); //建立会话 Session session = Session.getInstance(p); Message msg = new MimeMessage(session); //建立信息 msg.setFrom(new InternetAddress("tiwson@163.com")); //发件人 String toList = getMailList(to); InternetAddress[] iaToList = new InternetAddress().parse(toList); msg.setRecipients(Message.RecipientType.TO,iaToList); //收件人 msg.setSentDate(new Date()); // 发送日期 msg.setSubject("javamail测试邮件"); // 主题 msg.setText("注意,这是测试程序发的,请不要回复!"); //内容 // 邮件服务器进行验证 Transport tran = session.getTransport("smtp"); tran.connect("smtp.163.com", "tiwson", "9041160"); // bluebit_cn是用户名,xiaohao是密码 tran.sendMessage(msg, msg.getAllRecipients()); // 发送 System.out.println("邮件发送成功"); } catch (Exception e) { e.printStackTrace(); } } private String getMailList(String[] mailArray){ StringBuffer toList = new StringBuffer(); int length = mailArray.length; if(mailArray!=null && length <2){ toList.append(mailArray[0]); }else{ for(int i=0;i<length;i++){ toList.append(mailArray[i]); if(i!=(length-1)){ toList.append(","); } } } return toList.toString(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值