Springboot打造郵件服務

前言:

發(fā)送郵件,肯定是每個公司都會有的基本業(yè)務。很多公司都會選擇把發(fā)送郵件作為一個基礎服務,對外提供接口。直接調用就可發(fā)郵件了。但是我們都知道發(fā)送郵件耗時都比較長。那么今天就介紹下使用Spring boot+eventbus來打造一個簡單郵件服務

規(guī)劃接口列表

發(fā)送郵件的類型準備的有三種

  1. 發(fā)送普通郵件
  2. 發(fā)送html郵件
  3. 發(fā)送圖文郵件

還有一個細節(jié),如果我們同步的取發(fā)送郵件會有兩個問題。

  1. 接口響應時間比較長
  2. 遇到并發(fā)的情況,容易導致服務器壓力過大或者郵箱服務封ip

所以我們準備使用隊列來執(zhí)行發(fā)送郵件的操作??梢越鉀Q這個問題。隊列我選用的是Google的eventbus。是一款很輕量的隊列。直接走的內存

準備工作

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

    <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提供的發(fā)郵件的maven庫
  • guava:google提供的開源庫。里面包含來很多工具
  • lombok:可以幫你省去編寫實體類的工具

引入之后,我們還需要配置發(fā)送郵件所需要的必要配置
在application.properties中配置郵箱

spring.mail.host=smtp.mail.me.com //郵箱發(fā)送服務器
spring.mail.port=587//服務器端口
spring.mail.username=xxx6666@icloud.com//發(fā)件人郵箱
spring.mail.password=password//客戶端專用密碼
//如果和我一樣使用的icloud郵箱 還需要下列兩個配置,別的有的郵箱不需要
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

做到這里其實就已經完成了,發(fā)郵件所需要的配置了。但是我們是要用隊列來發(fā)送,所以還需要配置下隊列

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

封裝EmailService

準備好了之后,就可以直接來封裝發(fā)送郵件的業(yè)務了。之前有提到我們需要三個接口,同樣的,我們也需要三個service方法

@Service
public class EmailService {

    @Autowired
    private JavaMailSender javaMailSender;

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


    /**
     * 發(fā)送文本郵件
     * @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);
    }


    /**
     * 發(fā)送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);
    }

    /**
     * 發(fā)送圖文郵件
     * @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);
    }
}

隊列監(jiān)聽

既然封裝好了方法,那么就需要調用。調用的方式,其實就是將接口傳來的數(shù)據傳到隊列里。隊列的消費者接收到了消息就將消息拿來調用發(fā)送郵件的方法
我們首先創(chuàng)建一個消費類,用來接受消息,處理消息。

@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方法來拋消息。走到不同的方法里面是利用了類的多態(tài),拋入不同的實體類就可以進行區(qū)分了。走進了不同的方法,就調用相應Service方法。

控制器與測試

控制器部分,沒什么好說的,我就貼出圖文的代碼。其余代碼可以在我的碼云上面看

先看眼實體類

@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;
}

    /**
     * 發(fā)送圖文郵件
     * @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替換。最后將實體類拋入隊列。直接返回接口請求。隊列那邊就會排著隊搞定所有的郵件
下面來做個測試


請求接口

請求很迅速的返回了結果
然后去郵箱中查看結果


郵件結果

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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • http://liuxing.info/2017/06/30/Spring%20AMQP%E4%B8%AD%E6%...
    sherlock_6981閱讀 16,211評論 2 11
  • Spring Boot高級 內容概要 一、Spring Boot與緩存 二、Spring Boot與消息 三、Sp...
    順毛閱讀 457評論 0 2
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,681評論 1 32
  • 項目到了一定階段會出現(xiàn)一種甜蜜的負擔:業(yè)務的不斷發(fā)展與人員的流動性越來越大,代碼維護與測試回歸流程越來越繁瑣。這個...
    fdacc6a1e764閱讀 3,339評論 0 6
  • 年前刷抖音,看到很多人推《人間失格》這本書,書中的幾句比如:“如果能避開猛烈的歡喜,自不會有悲痛來襲”,甚得我喜歡...
    Sunshine_a4a5閱讀 927評論 0 0

友情鏈接更多精彩內容