Spring-boot搭建郵件服務

前言:

發送郵件,確定是每一個公司都會有的基本業務。不少公司都會選擇把發送郵件做爲一個基礎服務,對外提供接口。直接調用就可發郵件了。可是咱們都知道發送郵件耗時都比較長。那麼今天就介紹下使用Spring boot+eventbus來打造一個簡單郵件服務html

規劃接口列表

發送郵件的類型準備的有三種java

  1. 發送普通郵件
  2. 發送html郵件
  3. 發送圖文郵件

還有一個細節,若是咱們同步的取發送郵件會有兩個問題。git

  1. 接口響應時間比較長
  2. 遇到併發的狀況,容易致使服務器壓力過大或者郵箱服務封ip

因此咱們準備使用隊列來執行發送郵件的操做。能夠解決這個問題。隊列我選用的是Google的eventbus。是一款很輕量的隊列。直接走的內存github

準備工做

首先要在pom.xml中引入 須要使用的包spring

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
     </dependency>
     <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
     </dependency>
複製代碼
  • spring-boot-starter-mail :spring-boot提供的發郵件的maven庫
  • guava:google提供的開源庫。裏面包含來不少工具
  • lombok:能夠幫你省去編寫實體類的工具

引入以後,咱們還須要配置發送郵件所須要的必要配置 在application.properties中配置郵箱安全

spring.mail.host=smtp.mail.me.com //郵箱發送服務器
spring.mail.port=587//服務器端口
spring.mail.username=xxx6666@icloud.com//發件人郵箱
spring.mail.password=password//客戶端專用密碼
//若是和我同樣使用的icloud郵箱 還須要下列兩個配置,別的有的郵箱不須要
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
複製代碼

作到這裏其實就已經完成了,發郵件所須要的配置了。可是咱們是要用隊列來發送,因此還須要配置下隊列服務器

@Configuration
public class AsyncEventBusConfig {
    //實例化bean,採用單例形式注入容器
    @Bean
    @Scope("singleton")
    public AsyncEventBus asyncEventBus(){
        //建立線程池對象
        final ThreadPoolExecutor executor=executor();
        return new AsyncEventBus(executor);
    }
    //建立線程池方法
    private ThreadPoolExecutor executor(){
        return new
                ThreadPoolExecutor(2,
                2,0L,
                TimeUnit.MICROSECONDS,
                new LinkedBlockingQueue<>());
    }
}
複製代碼

封裝EmailService

準備好了以後,就能夠直接來封裝發送郵件的業務了。以前有提到咱們須要三個接口,一樣的,咱們也須要三個service方法併發

@Service
public class EmailService {

    @Autowired
    private JavaMailSender javaMailSender;

    /** * 發件人。這裏發件人通常是同使用的發件郵箱一致 */
    @Value("${spring.mail.username}")
    private String from;


    /** * 發送文本郵件 * @param to 收件人郵箱地址 * @param subject 主題 * @param content 內容 */
    public void sendTextMail(String to, String subject, String content) {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setTo(to);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setText(content);
        simpleMailMessage.setFrom(from);
        javaMailSender.send(simpleMailMessage);
    }


    /** * 發送html內容的郵件 * @param to 收件人 * @param htmlContent html內容 * @param subject 主題 * @throws MessagingException */
    public void sendHtmlMail(String to, String htmlContent, String subject) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
        messageHelper.setTo(to);
        messageHelper.setSubject(subject);
        messageHelper.setFrom(from);
        messageHelper.setText(htmlContent, true);
        javaMailSender.send(message);
    }

    /** * 發送圖文郵件 * @param to 收件人 * @param imgContent 圖文內容 * @param subject 主題 * @param rscId 資源id * @param imgPath 資源路徑 * @throws MessagingException */
    public void sendImgMail(String to, String imgContent, String subject, String rscId, String imgPath) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
        messageHelper.setTo(to);
        messageHelper.setSubject(subject);
        messageHelper.setFrom(from);
        messageHelper.setText(imgContent, true);
        messageHelper.addInline(rscId, new File(imgPath));
        javaMailSender.send(message);
    }
}
複製代碼

隊列監聽

既然封裝好了方法,那麼就須要調用。調用的方式,其實就是將接口傳來的數據傳到隊列裏。隊列的消費者接收到了消息就將消息拿來調用發送郵件的方法 咱們首先建立一個消費類,用來接受消息,處理消息。app

@Service
public class EventBusListener {

    /** * 引入bean */
    @Autowired
    private AsyncEventBus asyncEventBus;

    @Autowired
    private EmailService emailService;

    /** * 註冊服務類 */
    @PostConstruct
    public void init(){
        asyncEventBus.register(this);
    }

    /** * 線程安全,消費 文本消息 * @param textEmailDTO */
    @AllowConcurrentEvents
    @Subscribe
    public void sendTextMail(TextEmailDTO textEmailDTO){
        emailService.sendTextMail(
                textEmailDTO.getTo(),
                textEmailDTO.getSubject(),
                textEmailDTO.getContent()
        );
    }

    /** * 線程安全 消費 html消息 * @param htmlEmailDTO */
    @AllowConcurrentEvents
    @Subscribe
    public void sendHtmlMail(HtmlEmailDTO htmlEmailDTO){
        try {
            emailService.sendHtmlMail(
                    htmlEmailDTO.getTo(),
                    htmlEmailDTO.getHtmlContent(),
                    htmlEmailDTO.getSubject()
            );
        } catch (MessagingException e) {
           // nothing to do
        }
    }

    /** * 線程安全 消費 圖文消息 * @param imgEmailDTO */
    @AllowConcurrentEvents
    @Subscribe
    public void sendImgMail(ImgEmailDTO imgEmailDTO){
        try {
            emailService.sendImgMail(
                    imgEmailDTO.getTo(),
                    imgEmailDTO.getImgContent(),
                    imgEmailDTO.getSubject(),
                    imgEmailDTO.getRscId(),
                    imgEmailDTO.getImgPath()
            );
        } catch (MessagingException e) {
            // nothing to do
        }
    }
}
複製代碼

其實eventbus拋消息都是使用的post方法來拋消息。走到不一樣的方法裏面是利用了類的多態,拋入不一樣的實體類就能夠進行區分了。走進了不一樣的方法,就調用相應Service方法。async

控制器與測試

控制器部分,沒什麼好說的,我就貼出圖文的代碼。其他代碼能夠在個人github上面看

先看眼實體類

@Data
public class ImgEmailDTO implements Serializable {
    public ImgEmailDTO() {
    }

    /** * 圖片路徑 */
    private String imgPath;

    /** * 資源id */
    private String rscId;

    /** * 主題 */
    private String subject;

    /** * 圖片正文(一樣可使用html) */
    private String imgContent;

    /** * 收件人 */
    private String to;
}

複製代碼
/** * 發送圖文郵件 * @param request * @return */
    @RequestMapping(value = "/sendImgMail", method = RequestMethod.POST)
    public Result<Integer> sendImgMail(@RequestBody Request<ImgEmailDTO> request) {
        Result<Integer> result = Result.create();
        ImgEmailDTO imgEmailDTO=request.getData();
        StringBuilder sb=new StringBuilder();
        sb.append(imgEmailDTO.getImgContent());
        //cid:資源id。在spring中會自動綁定
        sb.append("<img src=\'cid:").append(imgEmailDTO.getRscId()).append("\'></img>");
        imgEmailDTO.setImgContent(sb.toString());
        asyncEventBus.post(imgEmailDTO);
        return result.success(1);
    }
複製代碼

圖文要稍微特殊一點,須要拼接下正文內容。而後將實體類中的content替換。最後將實體類拋入隊列。直接返回接口請求。隊列那邊就會排着隊搞定全部的郵件 下面來作個測試

請求接口
請求很迅速的返回告終果 而後去郵箱中查看結果
郵件結果

好了今天對郵件服務的介紹就寫到這裏。知識點並不深奧,主要介紹一個思路。若有不對的地方,請大神指出。謝謝

相關文章
相關標籤/搜索