1. 简介
Java的发送邮件的组合一直让人比较困惑,这里做一个简单的小结和说明一些注意事项。 
MimeBodyPart可以是文本、HTML、图片附件,也可以是MimeMultiPart。
MimeMultiPart是多个MimeBodyPart的组合,这样就可以通过嵌套的方式完成复杂邮件的组合。
2. sender与from
mimeMessage.setFrom(fromAddress);
mimeMessage.setSender(senderAddress);
from:表示邮件是谁想发的,必须和下面的transport连接的时候使用的user一致:
transport.connect(host, user, pass);
sender:sender表示发件人,邮件中可以看到发件人可以看到sender代表from发送,使用的用户名和密码还是from的。
如果想要让邮件显眼,一看就知道是谁发的,可以使用:
title<邮箱地址>
例如:
InternetAddress fromAddress = new InternetAddress(String.format("%s<%s>",MimeUtility.encodeText("技术部"),from));
MimeUtility.encodeText可以处理中文问题。
3. RecipientType
- Message.RecipientType.TO :接收
 - Message.RecipientType.CC :抄送
 - Message.RecipientType.BCC:密送
 
4. Multipart subtype
mimeMultipart.setSubType("related");
- mixed:混合关系,一般正文和附件组合使用mixed,如果不设置,javamail默认会使用mixed
 - related:关联关系,一般html引用了图片这类内嵌资源,正文和图片组合使用related
 - alternative:同时存在纯文本与超文本,使用boundary分割
 
邮件可能会分段,使用的是boundary中定义的字符串作为标识。
- 段体内的每个子段以:【--加boundary】行开始
 - 父段则以:【--加boundary加--】行结束
 - 不同段之间用空行分隔
 
大概像下面这样的:
Content-Type: multipart/mixed; 
    boundary="----=_Part_1_293907205.1610941392421"
------=_Part_1_293907205.1610941392421
Content-Type: multipart/related; 
    boundary="----=_Part_0_1259652483.1610941392409"
------=_Part_0_1259652483.1610941392409
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-ID: haha
可以使用:
mimeMessage.writeTo(new FileOutputStream("G:\\picture\\tmp.eml"));
将邮件保存到本地,然后使用文本编辑器打开查看。
5. Store与Folder
5.1 Store
Store表示存储邮件的服务器,接收邮件
// 存储邮件的服务器,采用pop3协议
Store store = session.getStore("pop3");
    
// 连接邮件服务器
store.connect(host,username,passworsd);
5.2 Folder
Folder表示收件箱目录对象
Folder folder = store.getFolder("tmp");
// 以只读的方式打开目录
folder.open(Folder.READ_ONLY);
 
// 获取目录下的邮件信息
Message message[ ] = folder.getMessages();
6. 示例
public enum MailConfig {
M163("mail.163.com","xxx@163.com","xxx");
    private String server;
    private String user;
    private String pass;
    MailConfig(String server, String user, String pass) {
        this.server = server;
        this.user = user;
        this.pass = pass;
    }
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public String getServer() {
        return server;
    }
    public void setServer(String server) {
        this.server = server;
    }
}
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class MailSenderHelper {
    public static Session getSession(MailConfig config){
        Properties properties = new Properties();
        properties.setProperty("mail.host", config.getServer());
        properties.setProperty("mail.transport.protocol", "smtp");
        properties.setProperty("mail.smtp.auth", "true");
        Session session = Session.getInstance(properties);
        session.setDebug(false);
        return session;
    }
    public static Transport getTransport(MailConfig config) throws MessagingException {
        Session session = getSession(config);
        Transport transport = session.getTransport();
        transport.connect(config.getServer(), config.getUser(), config.getPass());
        return transport;
    }
    public static void send(MailConfig config, MimeMessage mimeMessage) throws MessagingException {
        Transport transport = getTransport(config);
        transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
        transport.close();
    }
}
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.util.Date;
import java.util.List;
public class HtmlEmailHelper {
    private static final String TEXT_HTML_CHARSET_UTF_8 = "text/html;charset=UTF-8";
    private static final String UTF8 = "UTF-8";
    public static void sendHtmlEmail(
            MailConfig config,
            String from,
            String nickname,
            List<String> tos,
            String subject,
            String html,
            List<String> imgs,
            List<String> attachs
    ) throws Exception{
        Session session = MailSenderHelper.getSession(config);
        MimeMessage mimeMessage = new MimeMessage(session);
//        InternetAddress senderAddress = new InternetAddress(config.getUser());
//        InternetAddress fromAddress = new InternetAddress(from);
        InternetAddress fromAddress = new InternetAddress(String.format("%s<%s>",MimeUtility.encodeText("技术部"),config.getUser()));
        InternetAddress senderAddress = new InternetAddress(String.format("%s<%s>",MimeUtility.encodeText(nickname),from));
//        if(StringUtils.isNotBlank(nickname)){
//            mimeMessage.setFrom(new InternetAddress(String.format("%s<%s>",nickname,from)));
//        }else {
//            mimeMessage.setFrom(fromAddress);
//        }
        mimeMessage.setFrom(fromAddress);
        mimeMessage.setSender(senderAddress);
        for (String to : tos) {
            mimeMessage.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress(to));
        }
        mimeMessage.setSubject(subject,UTF8);
        DataHandler dh;
        FileDataSource fileDataSource;
        MimeMultipart mimeMultipart = new MimeMultipart();//html 与 图片
        // 添加图片部分
        if(imgs != null && imgs.size() > 0) {
            for (String img : imgs) {
                MimeBodyPart image = new MimeBodyPart();
                fileDataSource = new FileDataSource(img);
                dh = new DataHandler(fileDataSource);
                image.setDataHandler(dh);
                String name = dh.getName();
                int dotIndex = name.lastIndexOf(".");
                if(dotIndex != -1){
                    name = name.substring(0,dotIndex);
                }
                String contentID = MimeUtility.encodeText(name);
                image.setContentID(contentID);//<img src='cid:contentID'/>
                mimeMultipart.addBodyPart(image);
            }
        }
        // 添加HTML节点
        MimeBodyPart text = new MimeBodyPart();
        text.setContent(html, TEXT_HTML_CHARSET_UTF_8);
        // 将HTML和图片合成一个MimeMultiPart
        mimeMultipart.addBodyPart(text);
        // 因为html可能引用图片,所以关系设置为related,这样图片就不会显示在附件中
        mimeMultipart.setSubType("related");
        // 新建一个MimeMultipart存放最终内容:HTML图片部分 + 附件
        MimeMultipart mailMimeMultipart = new MimeMultipart();
        // 将HTML与图片的MimeMultiPart混合部分封装成一个MimeBodyPart
        MimeBodyPart txtImgMimeBodyPart = new MimeBodyPart();
        txtImgMimeBodyPart.setContent(mimeMultipart);
        // 添加HTML图片部分
        mailMimeMultipart.addBodyPart(txtImgMimeBodyPart);
        // 添加附件部分
        MimeBodyPart attachment;
        if(attachs != null && attachs.size() > 0) {
            for (String attach : attachs) {
                attachment = new MimeBodyPart();
                fileDataSource = new FileDataSource(attach);
                dh = new DataHandler(fileDataSource);
                attachment.setDataHandler(dh);
                attachment.setFileName(MimeUtility.encodeText(dh.getName()));
                mailMimeMultipart.addBodyPart(attachment);
            }
        }
        // HTML图片部分一般和附件没啥直接关系,所以关联关系设置为mixed
//        mailMimeMultipart.setSubType("mixed");
        mailMimeMultipart.setSubType("alternative");
        // 将MimeMessage的内容设置为组合好的最后的MimeMultipart部分
        mimeMessage.setContent(mailMimeMultipart);
        //设置邮件的发送时间,默认立即发送
        mimeMessage.setSentDate(new Date());
//        mimeMessage.saveChanges();
        //将邮件写入指定的路径
//        mimeMessage.writeTo(new FileOutputStream("G:\\picture\\tmp.eml"));
        MailSenderHelper.send(config,mimeMessage);
    }
}
 
 
 
 
 
 