SpingBoot使用JavaMail实现邮件的接收、发送

前言

最近项目需要集成mail,经过很长时间的摸索,也算是基本达成了项目中的要求了。
项目中主要是用到了 邮件发送,邮件接收

相关概念

IMAP
IMAP全称是Internet Mail Access Protocol(交互式邮件存取协议),与POP3一样都是一种邮件获取协议。它的主要作用是邮件客户端(例如iPhone、Foxmail)可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等。IMAP的功能是各处同步,即在网页、客户端、手持设备上对邮箱的操作,均多向同步。如果一封在网页中打开过的新邮件,在iPad上登录邮箱后,该邮件也是已读状态;一封邮件在iPhone上被彻底删除,在Foxmail登录邮箱后,将找不到该邮件。

SMTP
SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。

相关文档

https://javaee.github.io/javamail/docs/api/index.html
http://www.vue5.com/javamail_api/javamail_api_core_classes.html

导入依赖
        <dependency>
			<groupId>javax.mail</groupId>
			<artifactId>javax.mail-api</artifactId>
		</dependency>
		<dependency>
			<groupId>com.sun.mail</groupId>
			<artifactId>javax.mail</artifactId>
		</dependency>
邮件发送
  public void sendMail(SendMailParam sendMailParam, List<MultipartFile> files, MailSetting mailSetting) throws Exception {
        try {
            System.setProperty("mail.mime.splitlongparameters", "false");
            final JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
            javaMailSender.setUsername(mailSetting.getUsername());   //用于发送邮件的邮箱账号
            javaMailSender.setPassword(mailSetting.getPassword());   //用于发送邮件的邮箱密码
            javaMailSender.setHost(mailSetting.getSendHost());           //发送邮件的主机
            javaMailSender.setPort(mailSetting.getSendPort());           //发送邮件的端口
            javaMailSender.setProtocol(mailSetting.getSendProtocol());   //发送邮件的协议,默认值是:smtp
            javaMailSender.setDefaultEncoding(mailSetting.getSendProtocol());    //发送邮件的字符集,默认使用UTF-8
            final Properties mailProperties = new Properties();
            mailProperties.put("mail.smtp.auth", true);
            mailProperties.put("mail.debug", true);
            if (mailSetting.getSendEncryption().equals("STARTTLS")) {
                mailProperties.put("mail.smtp.starttls.enable", true);
            }
            if (mailSetting.getSendEncryption().equals("SSL")) {
                mailProperties.put("mail.smtp.ssl.enable", true);
            }

            javaMailSender.setJavaMailProperties(mailProperties);
            final MimeMessage mimeMessage = getMimeMessage(sendMailParam, javaMailSender, files,mailSetting.getUsername());
            javaMailSender.send(mimeMessage);
        } catch (MessagingException e) {
            System.out.println("メールの送信に失敗しました:"+e.getMessage());
        }
    }


 private MimeMessage getMimeMessage(SendMailParam sendMailParam,
                                       JavaMailSenderImpl javaMailSender, List<MultipartFile> files,String senderName) throws javax.mail.MessagingException {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
        mimeMessageHelper.setFrom(senderName);   
        mimeMessageHelper.setTo(sendMailParam.getTo());
        mimeMessageHelper.setCc(sendMailParam.getCc());
        mimeMessageHelper.setSubject(sendMailParam.getSubject());
        mimeMessageHelper.setText(sendMailParam.getContent(), true);
        try {
            if(files != null){
                for (MultipartFile file : files) {
                    String filename = file.getOriginalFilename();
                    mimeMessageHelper.addAttachment(filename, file);
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return mimeMessage;
    }

邮件接收

邮件接收 就是 获取收件夹(inbox)中的邮件
当然同样也可以 获取已发送的邮件

receiveMailParam

如果使用 @Data注解 需要导入 Lombok 包
MailSetting 主要就是 邮件配置的信息

@Data
public class ReceiveMailParam  {
   private String type;
   private long mailUID;
   private MailSetting mailSetting;
}
 @Data
public class MailSetting extends NewBaseEntity {
    private int msid;
    private String username;
    private String password;
    private String sendHost;
    private int sendPort;
    private String sendProtocol;
    private String receiveHost;
    private int receivePort;
    private String receiveProtocol;
    private String receiveEncryption;
    private String sendEncryption;
}
private Store imapConnection(ReceiveMailParam receiveMailParam) throws MessagingException {
        Properties props = new Properties();
        props.put("mail.imap.host", receiveMailParam.getMailSetting().getReceiveHost());
        props.put("mail.imap.port", receiveMailParam.getMailSetting().getReceivePort());
        props.put("mail.imap.auth", true);

        if (receiveMailParam.getMailSetting().getReceiveEncryption().equals("STARTTLS")) {
            props.put("mail.imap.starttls.enable", true);
        }
        if (receiveMailParam.getMailSetting().getReceiveEncryption().equals("SSL")) {
            props.put("mail.imap.ssl.enable", true);
        }

        Session session = Session.getInstance(props);

        HashMap IAM = new HashMap();
//带上IMAP ID信息,由key和value组成,例如name,version,vendor,support-email等。
        IAM.put("name","myname");
        IAM.put("version","1.0.0");
        IAM.put("vendor","myclient");
        IAM.put("support-email","testmail@test.com");

        IMAPStore store = (IMAPStore) session.getStore("imap");
        store.connect(receiveMailParam.getMailSetting().getUsername(), receiveMailParam.getMailSetting().getPassword());
        store.id(IAM);   //这个id信息也可以选择不要  这个主要是针对 网易邮箱的 

        return store;
    }



 public List<MailHistoryDto> receiveMail(ReceiveMailParam receiveMailParam) throws Exception {

        Store store = imapConnection(receiveMailParam);  //这一步就是 调用上面的方法 获取Store对象
        String folderName = "";
        if(receiveMailParam.getType().equals("inbox")){
            folderName = "INBOX";
        }else if (receiveMailParam.getType().equals("send")){
        //获取 已发送邮件夹的名字
        // 收件夹的名字是固定的  但是其他邮件夹名字是不同的 不同的邮箱 名字也会不同
            Folder defaultFolder = store.getDefaultFolder();
            List<Folder> allFolder = Arrays.asList(defaultFolder.list());  //获取所有的邮件夹
            folderName = allFolder.get(2).getFullName();
        }
        IMAPFolder folder = (IMAPFolder) store.getFolder(folderName);  //获取邮件夹
        folder.open(Folder.READ_ONLY);  //打开邮件夹 只读权限 
        Message[] messagess = folder.getMessages(); //获取邮件夹的所有邮件
        //现在获取到是message  而邮件的内容是需要通过解析的
         List<MailHistoryDto> mailHistoryDtoList = new ArrayList<>();
        //解析所有的邮件
        for (Message message : messagess) {
            MailHistoryDto mailHistoryDto = new MailHistoryDto();
            MimeMessage msg = (MimeMessage) message;
            mailHistoryDto.setMailUID(folder.getUID(msg));
            mailHistoryDto.setIsSeen(ParseMail.isSeen(msg));
            mailHistoryDto.setFrom(ParseMail.getFrom(msg));
            mailHistoryDto.setSubject(ParseMail.getSubject(msg));
            mailHistoryDto.setFrom(ParseMail.getFrom(msg));
            mailHistoryDto.setTo(ParseMail.getReceiveAddress(msg,Message.RecipientType.TO ));
            mailHistoryDto.setCc(ParseMail.getReceiveAddress(msg,Message.RecipientType.CC ));
            mailHistoryDto.setSendDate(ParseMail.getSentDate(msg,null));
            mailHistoryDto.setContainAttachment(ParseMail.isContainAttachment(msg));
            mailHistoryDto.setReplySign(ParseMail.isReplySign(msg));
            mailHistoryDto.setPriority(ParseMail.getPriority(msg));
            StringBuffer content = new StringBuffer(30);
            ParseMail.getMailTextContent(msg,content);
            mailHistoryDto.setContent(String.valueOf(content));
            if(receiveMailParam.getType().equals("inbox")){
                mailHistoryDto.setType("inbox");
            }else if (receiveMailParam.getType().equals("send")){
                mailHistoryDto.setType("send");
            }
            mailHistoryDtoList.add(mailHistoryDto);

        }
        if (folder != null){
            folder.close(true);
        }
        if (store != null) {
            store.close();
        }

        return mailHistoryDtoList;
解析邮件

ParseMail

package com.share.mailTemplate.service;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ParseMail {
    /**
     * 删除邮件
     *
     * @param messages 要解析的邮件列表
     */
    public static void deleteMessage(Message... messages) throws MessagingException, IOException {
        if (messages == null || messages.length < 1)
            throw new MessagingException("未找到要解析的邮件!");

        // 解析所有邮件
        for (int i = 0, count = messages.length; i < count; i++) {

            /**
             *   邮件删除
             */
            Message message = messages[i];
            String subject = message.getSubject();
            // set the DELETE flag to true
            message.setFlag(Flags.Flag.DELETED, true);
            System.out.println("Marked DELETE for message: " + subject);


        }
    }

    /**
     * 获得邮件主题
     *
     * @param msg 邮件内容
     * @return 解码后的邮件主题
     */
    public static String getSubject(MimeMessage msg) throws UnsupportedEncodingException, MessagingException {
        return MimeUtility.decodeText(msg.getSubject());
    }

    /**
     * 获得邮件发件人
     *
     * @param msg 邮件内容
     * @return 姓名 <Email地址>
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    public static String getFrom(MimeMessage msg) throws MessagingException, UnsupportedEncodingException {
        String from = "";
        Address[] froms = msg.getFrom();
        if (froms.length < 1)
            throw new MessagingException("没有发件人!");

        InternetAddress address = (InternetAddress) froms[0];
        String person = address.getPersonal();
        if (person != null) {
            person = MimeUtility.decodeText(person) + " ";
        } else {
            person = "";
        }
        from = person + "<" + address.getAddress() + ">";

        return from;
    }

    /**
     * 根据收件人类型,获取邮件收件人、抄送和密送地址。如果收件人类型为空,则获得所有的收件人
     * <p>Message.RecipientType.TO  收件人</p>
     * <p>Message.RecipientType.CC  抄送</p>
     * <p>Message.RecipientType.BCC 密送</p>
     *
     * @param msg  邮件内容
     * @param type 收件人类型
     * @return 收件人1 <邮件地址1>, 收件人2 <邮件地址2>, ...
     * @throws MessagingException
     */
    public static String getReceiveAddress(MimeMessage msg, Message.RecipientType type) throws MessagingException {
        StringBuffer receiveAddress = new StringBuffer();
        Address[] addresss = null;
        if (type == null) {
            addresss = msg.getAllRecipients();
        } else {
            addresss = msg.getRecipients(type);
        }

        if (addresss == null || addresss.length < 1)
            return null;
        for (Address address : addresss) {
            InternetAddress internetAddress = (InternetAddress) address;
            receiveAddress.append(internetAddress.toUnicodeString()).append(",");
        }

        receiveAddress.deleteCharAt(receiveAddress.length() - 1); //删除最后一个逗号

        return receiveAddress.toString();
    }

    /**
     * 获得邮件发送时间
     *
     * @param msg 邮件内容
     * @return yyyy年mm月dd日 星期X HH:mm
     * @throws MessagingException
     */
    public static String getSentDate(MimeMessage msg, String pattern) throws MessagingException {
        Date receivedDate = msg.getSentDate();
        if (receivedDate == null)
            return "";

        if (pattern == null || "".equals(pattern))
            pattern = "yyyy/MM/dd HH:mm ";

        return new SimpleDateFormat(pattern).format(receivedDate);
    }

    /**
     * 判断邮件中是否包含附件
     *
     * @return 邮件中存在附件返回true,不存在返回false
     * @throws MessagingException
     * @throws IOException
     */
    public static boolean isContainAttachment(Part part) throws MessagingException, IOException {
        boolean flag = false;
        if (part.isMimeType("multipart/*")) {
            MimeMultipart multipart = (MimeMultipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                String disp = bodyPart.getDisposition();
                if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {
                    flag = true;
                } else if (bodyPart.isMimeType("multipart/*")) {
                    flag = isContainAttachment(bodyPart);
                } else {
                    String contentType = bodyPart.getContentType();
                    if (contentType.indexOf("application") != -1) {
                        flag = true;
                    }

                    if (contentType.indexOf("name") != -1) {
                        flag = true;
                    }
                }

                if (flag) break;
            }
        } else if (part.isMimeType("message/rfc822")) {
            flag = isContainAttachment((Part) part.getContent());
        }
        return flag;
    }

    /**
     * 判断邮件是否已读
     *
     * @param msg 邮件内容
     * @return 如果邮件已读返回true, 否则返回false
     * @throws MessagingException
     */
    public static boolean isSeen(MimeMessage msg) throws MessagingException {
        return msg.getFlags().contains(Flags.Flag.SEEN);
    }

    /**
     * 判断邮件是否需要阅读回执
     *
     * @param msg 邮件内容
     * @return 需要回执返回true, 否则返回false
     * @throws MessagingException
     */
    public static boolean isReplySign(MimeMessage msg) throws MessagingException {
        boolean replySign = false;
        String[] headers = msg.getHeader("Disposition-Notification-To");
        if (headers != null)
            replySign = true;
        return replySign;
    }

    /**
     * 获得邮件的优先级
     *
     * @param msg 邮件内容
     * @return 1(High):紧急  3:普通(Normal)  5:低(Low)
     * @throws MessagingException
     */
    public static String getPriority(MimeMessage msg) throws MessagingException {
        String priority = "普通";
        String[] headers = msg.getHeader("X-Priority");
        if (headers != null) {
            String headerPriority = headers[0];
            if (headerPriority.indexOf("1") != -1 || headerPriority.indexOf("High") != -1)
                priority = "紧急";
            else if (headerPriority.indexOf("5") != -1 || headerPriority.indexOf("Low") != -1)
                priority = "低";
            else
                priority = "普通";
        }
        return priority;
    }



    public static String getTextMultipart(Part part) throws Exception{
        if(part.isMimeType("text/html")){
            String content = (String) part.getContent();
            return content;
        }else if(part.isMimeType("text/plain")){
            String content = (String) part.getContent();
            return content;
        }
        return "";
    }

    /**
     * 获得邮件文本内容
     *
     * @param part    邮件体
     * @param content 存储邮件文本内容的字符串
     * @throws MessagingException
     * @throws IOException
     */
    public static void getMailTextContent(Part part, StringBuffer content) throws MessagingException, IOException {
        // 如果是文本类型的附件,通过getContent方法可以取到文本内容,但这不是我们需要的结果,所以在这里要做判断
        boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
        if (part.isMimeType("text/*") && !isContainTextAttach) {
            content.append(part.getContent().toString());
        } else if (part.isMimeType("message/rfc822")) {
            getMailTextContent((Part) part.getContent(), content);
        } else if (part.isMimeType("multipart/*")) {
            Object mpart = part.getContent();
            if (mpart instanceof Multipart) {
                Multipart multipart = (Multipart) part.getContent();
                int partCount = multipart.getCount();
                for (int i = 0; i < partCount; i++) {
                    BodyPart bodyPart = multipart.getBodyPart(i);
                    getMailTextContent(bodyPart, content);
                }
            }
        }
    }
}
结语

以上就是 javamail 发送 和 接收 的过程了 如有疑问也可评论留言

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐