美文网首页
Javax.Mail 工具类

Javax.Mail 工具类

作者: wang6771264 | 来源:发表于2019-02-14 16:35 被阅读0次
  • 1.基础Model

package com.maple.common.utils.mail;

import javax.activation.DataHandler;
import java.util.List;
import java.util.Map;

import lombok.Data;

@Data
public class MailMessage {
    /**
     * 内容ID
     */
    private String contentID;
    /**
     * 主题
     */
    private String subject;
    /**
     * 内容(包括html)
     */
    private String content;
    /**
     * 文本格式类型(例子:text/html; charset=utf-8)
     */
    private String subType;
    /**
     * 图片传入,适用于HTML邮件,key:cid名称;value:文件路径
     */
    private Map<String, String> images;
    /**
     * 附件上传
     */
    private List<String> attachments;
    /**
     * 文件
     */
    private DataHandler dh;
    /**
     * 描述
     */
    private String description;
}

package com.maple.common.utils.mail;

import java.util.Map;

import lombok.Data;

/**
 * 填充模板的邮件实体
 */
@Data
public class MailTmplMessage extends MailMessage {
    private String tmplPath;
    private Map<String, String> params;
}
  • 2.辅助类

package com.maple.common.utils.mail;

import java.io.File;
import java.net.URL;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CacheEntity<T> {
    Logger logger = LoggerFactory.getLogger(getClass());
    Date date;
    URL url;
    long lastModified;
    long hit;
    long length;
    T t;

    public long getLastModified() {
        return lastModified;
    }

    public void setLastModified(long lastModified) {
        this.lastModified = lastModified;
    }

    public long getHit() {
        return hit;
    }

    public void setHit(long hit) {
        this.hit = hit;
    }

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public boolean validate(File file) {
        if (file != null) {
            if (file.lastModified() != this.lastModified) {
                return false;
            }
            if (file.length() != this.length) {
                return false;
            }
        }
        logger.debug("url {} hit {}", url, ++hit);
        return true;
    }

    public CacheEntity(URL url, File file, T t) {
        this.url = url;
        this.date = new Date(System.currentTimeMillis());
        this.hit = 0;
        if (file != null) {
            this.lastModified = file.lastModified();
            this.length = file.length();
        }
        this.t = t;
    }

    public String toString() {
        if (date == null) {
            return "Hit #" + hit;
        }
        return "Hit #" + hit + " since " + date;
    }
}

package com.maple.common.utils.mail;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.WeakHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbsFileCache<T> {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    WeakHashMap<String, CacheEntity<T>> cache;

    public AbsFileCache(int cacheSize) {
        cache = new WeakHashMap<String, CacheEntity<T>>(cacheSize);
    }
    
    public T get(String path) throws IOException {
        URL url = this.getClass().getClassLoader().getResource(path);
        if (url != null) {
            logger.info("load file:"+url);
            String protocol = url.getProtocol();
            File file = null;
            InputStream is = null;
            if ("jar".equals(protocol) || "zip".equals(protocol)) {
                String jarFile = url.getFile();
                int pos = jarFile.indexOf("!");
                if (pos > 0) {
                    jarFile = jarFile.substring(0, pos);
                }
                file = new File(jarFile);
                is = url.openStream();
            } else if ("file".equals(protocol)) {
                file = new File(url.getFile());
                is = new FileInputStream(file);
            } else {
                logger.warn("not support the protocol {} with {}", protocol, url);
            }
            CacheEntity<T> ce = cache.get(path);
            if (ce != null && ce.validate(file)) {
                return ce.getT();
            } else {
                try {
                    T t = createCache(is);
                    ce = new CacheEntity<T>(url, file, t);
                    cache.put(path, ce);
                    return t;
                } finally {
                    if (is != null) {
                        is.close();
                    }
                }
            }
        } else {
            logger.warn("not found the file {}", path);
        }
        return null;
    }

    protected abstract T createCache(InputStream is) throws IOException;
}

package com.maple.common.utils.mail;

import java.io.InputStream;
import java.io.InputStreamReader;

import groovy.text.StreamingTemplateEngine;
import groovy.text.Template;

public final class TemplateCache extends AbsFileCache<Template> {

    StreamingTemplateEngine templateEngine = new StreamingTemplateEngine();

    private TemplateCache() {
        super(256);
    }

    private static class TemplateCacheHolder {
        private static TemplateCache Ins = new TemplateCache();
    }

    public static TemplateCache getIns() {
        return TemplateCacheHolder.Ins;
    }

    @Override
    public Template createCache(InputStream is) {
        Template t;
        try {
            t = templateEngine.createTemplate(new InputStreamReader(is, "UTF-8"));
            return t;
        } catch (Exception e) {
            logger.error("create template error", e);
            throw new RuntimeException(e);
        }
    }

}


  • 3.邮件发送类

  Props参数配置可以在https://javaee.github.io/javamail/docs/api/中找到,一般邮件发送都是用smtp/pop3即可。*
  *使用groovy的模板引擎参数找不到会报错,不会填充完毕,最终选择使用Velocity来做,Spring有velociy的支持。
package com.maple.common.utils.mail;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.annotation.PostConstruct;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import com.alibaba.fastjson.JSON;
import com.sun.mail.imap.IMAPFolder;
import groovy.text.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

/**
 * 邮件工具类
 */
@Slf4j
@Component
public class MailService {
     @Autowired
     private Velocity velocity;

    private static final String username = "xxxx@qq.com";
    //此处需要注意的是,这里的密码是邮箱的第三方访问授权码,不是真正的邮箱密码
    private static final String password = "sfhfaqvyvfhzdjii";

    Authenticator auth = new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password);
        }
    };

    Properties props = new Properties();

    @PostConstruct
    public void init(){
        //基础参数设置
        props.put("mail.smtp.host", "smtp.qq.com");
        props.put("mail.imap.host", "imap.qq.com");
        //pop3参数设置
        props.put("mail.pop3.user", "2294808913@qq.com");
        props.put("mmail.pop3.host", "pop.qq.com");
        props.put("mail.pop3.ssl.enable", true);
        props.put("mail.pop3.port", 995);
        props.put("mail.smtp.port", 465);
        props.put("mail.smtp.ssl.enable", "true");

        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.debug", "true");
    }

    public void sendTmplEmail(String recipients, MailTmplMessage msg, Message.RecipientType type){
        StringWriter sw = new StringWriter();
        try {
            //参数找不到会报错,不可取
            Template t = TemplateCache.getIns().get(msg.getTmplPath());
            t.make(msg.getParams()).writeTo(sw);

            msg.setContent(sw.toString());
        } catch (IOException e) {
            log.error("File tmpl assembly failed! params:{}", JSON.toJSONString(msg.getParams()), e);
        }
        sendMail(recipients, msg, type);
    }

    /**
     * @param type:Message.RecipientType.TO常量表示收件人类型是邮件接收者
     *             Message.RecipientType.CC常量表示收件人类型是抄送者
     *             Message.RecipientType.BCC常量表示收件人的类型是密送着
     *
     */
    public void sendMail(String recipients, MailMessage msg, Message.RecipientType type) {
        // set any other needed mail.smtp.* properties here
        Session session = Session.getDefaultInstance(props, auth);
        // set the message content here
//        msg.setContent(mp);

        try {
            MimeMessage mimeMessage = new MimeMessage(session);
            mimeMessage.setFrom(username);

            mimeMessage.setSubject(msg.getSubject());

            //HTML页面
            if (msg.getSubType().contains("text/html")) {
                Multipart multipart = new MimeMultipart();
                mimeMessage.setContent(multipart);
                MimeBodyPart htmlBody = new MimeBodyPart();
                multipart.addBodyPart(htmlBody);
                htmlBody.setContent(msg.getContent(), msg.getSubType());

                //HTML内嵌图片
                if (!CollectionUtils.isEmpty(msg.getImages())) {
                    addImages(multipart, msg.getImages());
                }
            }else{
                mimeMessage.setText(msg.getContent());
            }

            //上传附件
            if (!CollectionUtils.isEmpty(msg.getAttachments())) {
                Multipart multipart;
                if(mimeMessage.getContent() != null){
                    multipart = (MimeMultipart)mimeMessage.getContent();
                }else{
                    multipart = new MimeMultipart();
                }

                for (String attachment : msg.getAttachments()) {
                    multipart.addBodyPart(createAttachment(attachment));
                }
            }

            mimeMessage.setSentDate(new Date());
            mimeMessage.setRecipients(type, recipients);

            Transport transport = session.getTransport();

            transport.send(mimeMessage, username, password);
        } catch (MessagingException e) {
            log.error("send mail failed! content! Email:{}", JSON.toJSONString(msg), e);
        } catch (IOException e) {
            log.error("create attachment failed! Email:{}", JSON.toJSONString(msg), e);
        }
    }

    /**
     * 上传附件
     */
    private BodyPart createAttachment(String attachment){
        try {
            MimeBodyPart mbp = new MimeBodyPart();
            DataSource fds = new FileDataSource(attachment);
            mbp.setFileName(MimeUtility.encodeText(fds.getName()));
            DataHandler dh = new DataHandler(fds);

            mbp.setDataHandler(dh);
            return mbp;
        } catch (MessagingException e) {
            log.error("add attachment failed! fileName:{}", attachment, e);
        } catch (UnsupportedEncodingException e) {
            log.error("file format error! fileName:{}", attachment, e);
        }

        return null;
    }

    /**
     * html文件添加图片
     * 注意:如果在html文本中未标记cid,文件会被当做附件处理
     */
    private void addImages(Multipart multipart, Map<String, String> images) {
        for (Entry<String, String> entry : images.entrySet()) {
            MimeBodyPart imageBody = new MimeBodyPart();
            try {
                imageBody.setContentID(entry.getKey());
                DataSource fds = new FileDataSource(entry.getValue());
                imageBody.setFileName(MimeUtility.encodeText(fds.getName()));
                DataHandler dh = new DataHandler(fds);
                imageBody.setDataHandler(dh);

                multipart.addBodyPart(imageBody);
            } catch (MessagingException e) {
                log.error("add image failed! ContentID:{}", entry.getKey(), e);
            } catch (UnsupportedEncodingException e) {
                log.error("file format error! fileName:{}", entry.getValue(), e);
            }
        }
    }

    /**
     * 添加附件(文件形式添加)
     * @param file
     */
    public void addAttachment(File file){
        DataSource ds = new FileDataSource(file) {
            public String getContentType() {
                return "mytype/mysubtype";
            }
        };
        MimeBodyPart mbp = new MimeBodyPart();
        try {
            mbp.setDataHandler(new DataHandler(ds));
            //早期的javamail可以使用该方法编码
            mbp.setFileName(MimeUtility.encodeText(file.getName()));
            //对应的解码
//            String filename = MimeUtility.decodeText(mbp.getFileName());
            mbp.setFileName(file.getName());
            mbp.setDisposition(Part.ATTACHMENT);
        } catch (MessagingException e) {
            log.error("add attachment failed!", e);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加附件(byte形式添加)
     * @param data
     */
    public void addAttachment(String data){
        MimeBodyPart mbp = new MimeBodyPart();
        data = "any ASCII data";
        try {
            DataSource ds = new ByteArrayDataSource(data, "application/x-any");
            mbp.setDataHandler(new DataHandler(ds));
        } catch (MessagingException e) {
            log.error("add ASCII data failed!", e);
        } catch (IOException e) {
            log.error("read byte data failed! data:{}", data, e);
        }
    }
}
  • 4.测试类

package com.maple.example;

import javax.mail.Message.RecipientType;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import com.maple.common.utils.mail.MailService;
import com.maple.common.utils.mail.MailTmplMessage;
import com.maple.common.utils.mail.TemplateCache;
import groovy.text.Template;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
//@SpringBootTest
public class StudyApplicationTests {

    @Test
    public void contextLoads() {

    }

    //    @Autowired
    private MailService mailService = new MailService();

    @Test
    public void sendMailTest() {
        MailTmplMessage msg = new MailTmplMessage();
        msg.setSubject("测试html邮件主题");

        Map<String, String> map = new HashMap<>();
        map.put("title", "测试邮件标题");
        map.put("first", "大写头");
        map.put("testMan", "王威");

        msg.setParams(map);

        //html照片
        String userDir = System.getProperties().get("user.dir").toString();

        Map<String, String> images = new HashMap<>();
        images.put("image", userDir + "/src/main/resources/img/test_email.jpg");
        images.put("email2", userDir + "/src/main/resources/img/email2.png");

        msg.setImages(images);
        msg.setTmplPath("templates/mail/testMail.html");
        msg.setSubType("text/html; charset=utf-8");
        msg.setDescription("Maple test send!");

        mailService.sendTmplEmail("858869180@qq.com,2294808913@qq.com", msg, RecipientType.TO);
    }

    /**
     * 参数找不到会报错,不可取
     */
    @Test
    public void tmplGroovyTest(){
        Map<String, String> map = new HashMap<>();
        map.put("title", "测试邮件标题");
        map.put("first", "大写头");
        map.put("testMan", "王威");

        try {
            Template t = TemplateCache.getIns().get("templates/mail/testMail.html");
            StringWriter sw = new StringWriter();
            t.make(map).writeTo(sw);
            System.out.println(sw.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 5.配置文件

    • 5.1 pom文件

        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>javax.mail-api</artifactId>
            <version>1.6.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all -->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>${groovy.version}</version>
            <type>pom</type>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-velocity</artifactId>
        </dependency>
  • 5.2 velocity配置文件

directive.foreach.counter.name = velocityCount
directive.foreach.counter.initial.value = 1

input.encoding=UTF-8
output.encoding=UTF-8
Velocity.ENCODING_DEFAULT=UTF-8
Velocity.INPUT_ENCODING=UTF-8
Velocity.OUTPUT_ENCODING=UTF-8

default.contentType=text/html; charset=UTF-8 

#layout  
tools.view.servlet.layout.directory=/WEB-INF/view/layout/ 
  本片文章仅作为记录,如有错误,请评论指出多多交流谢谢!

相关文章

网友评论

      本文标题:Javax.Mail 工具类

      本文链接:https://www.haomeiwen.com/subject/wdpkeqtx.html