Springboot从入门到放弃之邮件发送

1.概述

日常开发中,消息通知是比较常见的一种功能。比如在你购买完火车票之后,会给你发送一条短信;再比如某些网站你登陆后,会给你发一封确认邮件,等等等等。还有一些特殊场景,需要告警信息推送功能,来及时发现并解决一些问题。本文将基于springboot环境,实现邮件发送功能,并基于此功能,实现一个有意思的案例,加强应用性。

2.发送邮件功能实现

javaEE中提供了专门的包用于发送邮件(JavaMail),spring对JavaMail进行了封装,并提供了专用的接口org.springframework.mail.javamail.JavaMailSender来实现邮件发送功能,springboot也为此提供了自动化配置,同时提供了对应接口,方便开箱即用。实现发送邮件的关键步骤如下:

2.1 添加依赖

引入以下pom文件:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.2 新增配置文件

#邮箱服务器地址,这个根据自己使用什么邮箱有区别,这里选用的是网易邮箱,平时使用较多的可能有qq、126、火狐等
spring.mail.host=smtp.163.com
spring.mail.port=25
#编码方式
spring.mail.default-encoding=UTF-8
#邮箱登陆用户名
spring.mail.username=test0220@163.com
#第三方登陆授权码
spring.mail.password=123456
#https需要开启
spring.mail.properties.mail.stmp.ssl.enable=true
spring.mail.properties.mail.stmp.ssl.required=true
#邮件接收时间的限制,单位毫秒
spring.mail.properties.mail.stmp.timeout=10000
#连接时间的限制,单位毫秒
spring.mail.properties.mail.stmp.connectiontimeout=10000
#邮件发送时间的限制,单位毫秒
spring.mail.properties.mail.stmp.writetimeout=10000
#发送者账号
mail.sender=marin@163.com

上述第三方登陆授权码与平时的邮箱登陆密码不是一样的,授权码是第三方客户端登陆邮箱的密码,授权码的获取需要去对应的邮箱官网进行开启POP3/SMTP以及IMAP/SMTP服务,由于邮箱种类较多,这里仅以网易邮箱为例,具体操作如下图所示:
在这里插入图片描述
在这里插入图片描述

2.3 编写工具类

2.3.1 编写接口MailService

public interface MailService {
	//简单文本邮件
    String sendSimpleMailMessage(String destination, String subject, String content);
	//html邮件
    String sendMimeMessage(String destination, String subject, String content);
	//带附件的邮件
    String sendMineMessageWithFile(String destination, String subject, String content, String filePath);
	//html邮件加附件
    String sendMimeMessageWithAttachment(String destination, String subject, String content, Map<String, String> maps);

}

2.3.2 实现接口MailServiceImpl

package com.eckey.lab.service.impl;

import com.eckey.lab.service.MailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Map;

@Slf4j
@Service
public class MailServiceImpl implements MailService {

    @Autowired
    private JavaMailSender mailSender;

    @Value("${mail.sender}")
    private String sender;

    @Override
    public String sendSimpleMailMessage(String destination, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(sender);
        message.setTo(destination);
        message.setSubject(subject);
        message.setText(content);
        try {
            mailSender.send(message);
        } catch (Exception e) {
            log.error("发送简单邮件时发生异常!", e);
        }
        return "success";
    }

    @Override
    public String sendMimeMessage(String destination, String subject, String content) {
        MimeMessage message = mailSender.createMimeMessage();
        try {
            //true表示需要创建一个multipart message
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(destination);
            helper.setSubject(subject);
            helper.setText(content, true);
            mailSender.send(message);
        } catch (MessagingException e) {
            log.error("发送MimeMessge时发生异常!", e);
        }
        return "success";
    }

    @Override
    public String sendMineMessageWithFile(String destination, String subject, String content, String filePath) {
        MimeMessage message = mailSender.createMimeMessage();
        try {
            //true表示需要创建一个multipart message
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(destination);
            helper.setSubject(subject);
            helper.setText(content, true);
            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = file.getFilename();
            helper.addAttachment(fileName, file);
            mailSender.send(message);
        } catch (MessagingException e) {
            log.error("发送带附件的MimeMessge时发生异常!", e);
        }
        return "success";
    }

    @Override
    public String sendMimeMessageWithAttachment(String destination, String subject, String content, Map<String, String> maps) {
        MimeMessage message = mailSender.createMimeMessage();
        try {
            //true表示需要创建一个multipart message
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(sender);
            helper.setTo(destination);
            helper.setSubject(subject);
            helper.setText(content, true);

            for (Map.Entry<String, String> entry : maps.entrySet()) {
                FileSystemResource file = new FileSystemResource(new File(entry.getValue()));
                helper.addInline(entry.getKey(), file);
            }
            mailSender.send(message);
        } catch (MessagingException e) {
            log.error("发送带静态文件的MimeMessge时发生异常!", e);
        }
        return "success";
    }
}

2.3.3 编写控制器测试

package com.eckey.lab.controller;

import com.eckey.lab.service.MailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/mail")
public class MailController {

    @Autowired
    private MailService mailService;

    //1812989950@qq.com
    private static final String DESTINATION = "123456@qq.com";

    private static final String SUBJECT = "这是一封爱的邮件!";

    private static final String CONTENT = "横眉冷对千夫指,俯首甘为孺子牛!";

    @PostMapping("/simple")
    public String sendSimpleMail() {
        log.info("发送简单邮件");
        return mailService.sendSimpleMailMessage(DESTINATION, SUBJECT, CONTENT);
    }

    @PostMapping("/mine")
    public String sendMineMail() {
        log.info("发送HTML邮件!");
        return mailService.sendMimeMessage(DESTINATION, SUBJECT, "<h1>" + CONTENT + "</h1>");
    }

    @PostMapping("/file")
    public String sendMailWithFile() throws FileNotFoundException {
        log.info("发送text邮件!");
        String path = "test.txt";
        File file = ResourceUtils.getFile("classpath:test.txt");
        String filePath = file.getAbsolutePath();
        return mailService.sendMineMessageWithFile(DESTINATION, SUBJECT, CONTENT, filePath);
    }

    @PostMapping("/all")
    public String sendMimeMessageWithAttachment() throws FileNotFoundException {
        log.info("发送带附件的邮件!");
        String htmlStr = "<html><body>测试:图片1 <br> <img src=\'cid:pic1\'/> <br>图片2 <br> <img src=\'cid:pic2\'/></body></html>";
        Map<String, String> rscIdMap = new HashMap<>(2);
        rscIdMap.put("pic1", ResourceUtils.getFile("classpath:img/redis.jpg").getAbsolutePath());
        rscIdMap.put("pic2", ResourceUtils.getFile("classpath:img/hbase.jpg").getAbsolutePath());
        return mailService.sendMimeMessageWithAttachment(DESTINATION, SUBJECT, htmlStr, rscIdMap);
    }
}

2.3.4 测试结果如下

1.简单邮件
在这里插入图片描述
2.HTML邮件
在这里插入图片描述
3.带附件的邮件
在这里插入图片描述
4.带图片的邮件
在这里插入图片描述

3.一个让女朋友爱到不能自拔的案例

为了充分发挥学以致用的精神,我们结合上述邮件案例来实现一个小需求。需求如下:每天定时发送一封邮件给女朋友,邮件的内容需要包括时间、当前城市、天气情况、以及一首爱的诗歌。实现这个需求包含以下条件:

1.需要一个可以实时获取天气的网站
http://wthrcdn.etouch.cn/weather_mini?city=
2.需要编写一个邮件模板
3.需要定时任务定时执行
4.需要每天写不同诗歌(可以建立一个诗歌库,每天定时获取一条记录)

3.1 编写天气信息获取接口

public interface WeatherService {

    Weather getWeatherInfo(String city);

}

3.2 实现天气信息获取接口

package com.eckey.lab.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.eckey.lab.entity.TomorrowWeather;
import com.eckey.lab.entity.Weather;
import com.eckey.lab.entity.YesterdayWeather;
import com.eckey.lab.service.WeatherService;
import com.eckey.lab.util.RestTemplateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
public class WeatherServiceImpl implements WeatherService {

    @Value("${weather.url}")
    private String weatherUrl;

    @Autowired
    private RestTemplateUtil restTemplateUtil;

    @Override
    public Weather getWeatherInfo(String city) {
        String url = weatherUrl + city;
        String result = restTemplateUtil.sendGet(url);
        log.info("weather info:{}", result);
        JSONObject jsonObject = JSON.parseObject(result);
        Weather weather = new Weather();
        if (jsonObject.getIntValue("status") == 1000 && jsonObject.getString("desc").equals("OK")) {
            String data = jsonObject.getString("data");
            JSONObject weatherInfo = JSON.parseObject(data);
            weather.setCity(city);
            if (StringUtils.isNoneBlank(data)) {
                YesterdayWeather yesterdayWeather = JSON.parseObject(weatherInfo.getString("yesterday"), YesterdayWeather.class);
                weather.setYesterday(yesterdayWeather);
            }
            String ganmao = weatherInfo.getString("ganmao");
            weather.setGanmao(ganmao);
            weather.setWendu(weatherInfo.getString("wendu"));
            String forecast = weatherInfo.getString("forecast");
            List<TomorrowWeather> tomorrowWeathers = JSON.parseArray(forecast, TomorrowWeather.class);
            TomorrowWeather tomorrowWeather = tomorrowWeathers.get(0);
            weather.setCurrentWeather(tomorrowWeather);
            weather.setTomorrowWeathers(tomorrowWeathers);
            log.info("weather info :{}", JSON.toJSONString(weather));
        }
        return weather;
    }
}

获取今日天气实体:

package com.eckey.lab.entity;
import lombok.Data;
import java.io.Serializable;

@Data
public class TomorrowWeather implements Serializable {

    /**
     * 日期
     */
    private String date;

    /**
     * 最高温度
     */
    private String high;

    /**
     * 风力
     */
    private String fengli;

    /**
     * 最低温度
     */
    private String low;

    /**
     * 风向
     */
    private String fengxiang;

    /**
     * 天气情况(晴天、多云、小雨)
     */
    private String type;
}

昨日天气实体:

package com.eckey.lab.entity;

import lombok.Data;
import lombok.ToString;

import java.io.Serializable;

@Data
@ToString
public class YesterdayWeather implements Serializable {

    /**
     * 日期
     */
    private String date;

    /**
     * 最高温度
     */
    private String high;

    /**
     * 风向
     */
    private String fx;

    /**
     * 最低温度
     */
    private String low;

    /**
     * 风力
     */
    private String fl;

    /**
     * 天气情况
     */
    private String type;
}

所有天气信息实体(包括昨日、今日,未来7日天气):

package com.eckey.lab.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
public class Weather implements Serializable {

    /**
     * 城市
     */
    private String city;

    /**
     * 昨天天气
     */
    private YesterdayWeather yesterday;

    /**
     * 根据天气温馨提示语
     */
    private String ganmao;

    /**
     * 当前温度
     */
    private String wendu;

    /**
     * 未来天气
     */
    private List<TomorrowWeather> tomorrowWeathers;

    /**
     * 今日天气
     */
    private TomorrowWeather currentWeather;

}

3.3 编写邮件工具类

package com.eckey.lab.util;

import com.eckey.lab.entity.TomorrowWeather;
import com.eckey.lab.entity.Weather;
import com.eckey.lab.enums.MonthEnum;
import com.eckey.lab.enums.WeatherEnum;
import com.eckey.lab.service.MailService;
import com.eckey.lab.service.WeatherService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

@Slf4j
@Component
public class MailUtil {

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private MailService mailService;

    @Autowired
    private WeatherService weatherService;

    private static final String DESTINATION = "18@qq.com";

    private static final String SUBJECT = "这是一封爱的邮件!";

    public void sendSimpleMail(String city) {
        Weather weatherInfo = weatherService.getWeatherInfo(city);
        Context context = new Context();
        HashMap<String, Object> maps = new HashMap<>();
        Date date = new Date();
        maps.put("week", getWeek(date));
        maps.put("city", city);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String format = simpleDateFormat.format(date);
        String[] months = format.split("-");
        String internal = MonthEnum.getInternal(Integer.valueOf(months[1]));
        StringBuffer stringBuffer = new StringBuffer(months[2]).append(" ").append(internal).append(" ").append(months[0]);
        maps.put("date", stringBuffer);
        if (weatherInfo != null) {
            TomorrowWeather currentWeather = weatherInfo.getCurrentWeather();
            if (StringUtils.isNotBlank(currentWeather.getHigh())) {
                maps.put("high", getTemperature(currentWeather.getHigh()));
            }
            if (StringUtils.isNotBlank(currentWeather.getLow())) {
                maps.put("low", getTemperature(currentWeather.getLow()));
            }
            if (StringUtils.isNotBlank(weatherInfo.getGanmao())) {
                maps.put("message", weatherInfo.getGanmao());
            }
            if (StringUtils.isNotBlank(currentWeather.getFengxiang())) {
                maps.put("fengxiang", currentWeather.getFengxiang());
            }
            if (StringUtils.isNotBlank(currentWeather.getType())) {
                String type = currentWeather.getType();
                maps.put("type", type);
                if (type.contains("晴")) {
                    maps.put("icon", WeatherEnum.SUNNY);
                } else if (type.contains("雨")) {
                    maps.put("icon", WeatherEnum.RAINY);
                } else if (type.contains("雪")) {
                    maps.put("icon", WeatherEnum.SNOW);
                } else {
                    maps.put("icon", WeatherEnum.CLOUD);
                }
            }
            if (StringUtils.isNotBlank(currentWeather.getFengli())) {
                String[] result = currentWeather.getFengli().split("\\[");
                String[] split = result[2].split("\\]");
                maps.put("fengli", split[0]);
            }

        }
        context.setVariables(maps);
        String content = this.templateEngine.process("mail", context);
        mailService.sendMimeMessage(DESTINATION, SUBJECT, content);
        mailService.sendMimeMessage("2@qq.com",SUBJECT,content);
    }

    public String getTemperature(String str) {
        String trim = str.trim();
        String[] strings = trim.split(" ");
        if (strings.length == 2) {
            return strings[1];
        } else
            return "10";
    }

    //根据日期取得星期几
    public static String getWeek(Date date) {
        String[] weeks = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (week_index < 0) {
            week_index = 0;
        }
        return weeks[week_index];
    }
}

3.4 编写定时任务

package com.eckey.lab.scheduler;

import com.eckey.lab.service.MailService;
import com.eckey.lab.service.WeatherService;
import com.eckey.lab.util.MailUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
@Component
public class MyScheduler {

    @Autowired
    private MailUtil mailUtil;

    public static final String city = "杭州";

    //每天上午9点执行 
    @Scheduled(cron = "0 0 9 * * ?")
    public void sendMessage() {
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format(date);
        mailUtil.sendSimpleMail(city);
    }
}

3.5 邮件模板

邮件模板选择使用thymeleaf,将获取到的天气信息和诗歌信息写入模板中,前端模板如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/feather-icons"></script>
    <style>
        @import url('https://fonts.googleapis.com/css?family=Montserrat:400,700,900&display=swap');
        :root {
            --gradient: linear-gradient( 135deg, #72EDF2 10%, #5151E5 100%);
        }

        * {
            -webkit-box-sizing: border-box;
            box-sizing: border-box;
            line-height: 1.25em;
        }

        .clear {
            clear: both;
        }

        body {
            margin: 0;
            width: 100%;
            height: 100vh;
            font-family: 'Montserrat', sans-serif;
            background-color: #ffffff;
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-align: center;
            -ms-flex-align: center;
            align-items: center;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            justify-content: center;
        }

        .container {
            border-radius: 25px;
            -webkit-box-shadow: 0 0 70px -10px rgba(0, 0, 0, 0.2);
            box-shadow: 0 0 70px -10px rgba(0, 0, 0, 0.2);
            background-color: #ffffff;
            color: #000000;
            height: 400px;
        }

        .weather-side {
            position: relative;
            height: 100%;
            border-radius: 25px;
            background-image: url("//repo.bfw.wiki/bfwrepo/image/5f26af591b919.png");
            width: 300px;
            -webkit-box-shadow: 0 0 20px -10px rgba(0, 0, 0, 0.2);
            box-shadow: 0 0 20px -10px rgba(0, 0, 0, 0.2);
            -webkit-transition: -webkit-transform 300ms ease;
            transition: -webkit-transform 300ms ease;
            -o-transition: transform 300ms ease;
            transition: transform 300ms ease;
            transition: transform 300ms ease, -webkit-transform 300ms ease;
            -webkit-transform: translateZ(0) scale(1.02) perspective(1000px);
            transform: translateZ(0) scale(1.02) perspective(1000px);
            float: left;
        }

        .weather-side:hover {
            -webkit-transform: scale(1.1) perspective(1500px) rotateY(10deg);
            transform: scale(1.1) perspective(1500px) rotateY(10deg);
        }

        .weather-gradient {
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            background-image: var(--gradient);
            border-radius: 25px;
            opacity: 0.8;
        }

        .date-container {
            position: absolute;
            top: 25px;
            left: 25px;
        }

        .date-dayname {
            margin: 0;
        }

        .date-day {
            display: block;
        }

        .location {
            display: inline-block;
            margin-top: 10px;
        }

        .location-icon {
            display: inline-block;
            height: 0.8em;
            width: auto;
            margin-right: 5px;
        }

        .weather-container {
            position: absolute;
            bottom: 25px;
            left: 25px;
        }

        .weather-icon.feather {
            height: 60px;
            width: auto;
        }

        .weather-temp {
            margin: 0;
            font-weight: 700;
            font-size: 4em;
        }

        .weather-desc {
            margin: 0;
        }

        .info-side {
            position: relative;
            float: left;
            height: 100%;
            padding-top: 25px;
        }

        .today-info {
            padding: 15px;
            margin: 0 25px 25px 25px;
            /* 	box-shadow: 0 0 50px -5px rgba(0, 0, 0, 0.25); */
            border-radius: 10px;
        }

        .today-info>div:not(:last-child) {
            margin: 0 0 10px 0;
        }

        .today-info>div .title {
            float: left;
            font-weight: 700;
        }

        .today-info>div .value {
            float: right;
        }

        .week-list {
            list-style-type: none;
            padding: 0;
            margin: 10px 35px;
            -webkit-box-shadow: 0 0 50px -5px rgba(0, 0, 0, 0.25);
            box-shadow: 0 0 50px -5px rgba(0, 0, 0, 0.25);
            border-radius: 10px;
            background: #000000;
        }

        .week-list>li {
            float: left;
            padding: 15px;
            cursor: pointer;
            -webkit-transition: 200ms ease;
            -o-transition: 200ms ease;
            transition: 200ms ease;
            border-radius: 10px;
        }

        .week-list>li:hover {
            -webkit-transform: scale(1.1);
            -ms-transform: scale(1.1);
            transform: scale(1.1);
            background: #fff;
            color: #222831;
            -webkit-box-shadow: 0 0 40px -5px rgba(0, 0, 0, 0.2);
            box-shadow: 0 0 40px -5px rgba(0, 0, 0, 0.2)
        }

        .week-list>li.active {
            background: #fff;
            color: #222831;
            border-radius: 10px;
        }

        .week-list>li .day-name {
            display: block;
            margin: 10px 0 0 0;
            text-align: center;
        }

        .week-list>li .day-icon {
            display: block;
            height: 30px;
            width: auto;
            margin: 0 auto;
        }

        .week-list>li .day-temp {
            display: block;
            text-align: center;
            margin: 10px 0 0 0;
            font-weight: 700;
        }

        .location-container {
            padding: 25px 35px;
        }

        .location-button {
            outline: none;
            width: 100%;
            -webkit-box-sizing: border-box;
            box-sizing: border-box;
            border: none;
            border-radius: 15px;
            padding: 10px;
            font-family: 'Montserrat', sans-serif;
            background-image: var(--gradient);
            color: #ffffff;
            font-weight: 700;
            -webkit-box-shadow: 0 0 30px -5px rgba(0, 0, 0, 0.25);
            box-shadow: 0 0 30px -5px rgba(0, 0, 0, 0.25);
            cursor: pointer;
            -webkit-transition: -webkit-transform 200ms ease;
            transition: -webkit-transform 200ms ease;
            -o-transition: transform 200ms ease;
            transition: transform 200ms ease;
            transition: transform 200ms ease, -webkit-transform 200ms ease;
        }

        .location-button:hover {
            -webkit-transform: scale(0.95);
            -ms-transform: scale(0.95);
            transform: scale(0.95);
        }

        .location-button .feather {
            height: 1em;
            width: auto;
            margin-right: 5px;
        }
    </style>

</head>
<body translate="no">
<div class="container">
    <div class="weather-side">
        <div class="weather-gradient"></div>
        <div class="date-container">
            <h2 class="date-dayname" th:text="${week}"></h2><span class="date-day" th:text="${date}"></span><i class="location-icon" data-feather="map-pin"></i><span class="location" th:text="${city}">杭州</span>
        </div>
        <div class="weather-container">
            <i class="weather-icon" th:attr="data-feather=${icon}"></i>
            <h1 class="weather-temp" th:text="${high}"></h1>
            <h3 class="weather-desc" th:text="${type}"></h3>
        </div>
    </div>
    <div class="info-side">
        <div class="today-info-container">
            <div class="today-info">
                <div class="precipitation"> <span class="title">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;向:</span><span class="value" th:text="${fengxiang}"></span>
                    <div class="clear"></div>
                </div>
                <div class="humidity"> <span class="title">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;力:</span><span class="value" th:text="${fengli}"></span>
                    <div class="clear"></div>
                </div>
                <div class="wind"> <span class="title">最低温度:</span><span class="value" th:text="${low}"></span>
                    <div class="clear"></div>
                </div>
            </div>
        </div>
        <div class="week-container" style="padding: 0px 40px">
            <p>热情的太阳是我迷恋你的天气,</p>
            <p>阴沉的乌云是我挂念你的心情,</p>
            <p>绚丽的彩虹是我爱你的痕迹。</p>
        </div>
        <div class="location-container">
            <button class="location-button"><span th:text="${message}"></span></button>
        </div>
    </div>
</div>

<script id="rendered-js">
    feather.replace();
</script>
</body>
</html>

3.6 邮件测试案例

在这里插入图片描述

4.小结

1.发送邮件一封邮件需要几个关键步骤:引入依赖、开启第三方授权码、引入配置等;
2.邮件的主要类型包括简单文本文件、html邮件、附件邮件、HTML附件邮件;
3.上述案例中,诗歌模块可以进一步优化:通过将每一首三行情书进行入库操作,每天定时获取一条记录,并将该条记录id存入缓存,第二天先获取缓存中的id,并增加指定步长,再利用新id查询数据库记录,保证每一天不一样(这里的前提是:数据库中有足够的诗歌数据,该数据的主键按指定规则递增);
4.邮件模板选择使用thymeleaf,其实就是定好HTML模板,每次将获取到的指定数据写入即可;
5.上述案例主要展示关键代码,完整版代码可参考下面的git地址。

5.参考文献

1.https://juejin.cn/post/6844903827477364744
2.https://juejin.cn/post/6844903825053057037
3.https://juejin.cn/post/6844903813820710920

6.项目地址

https://gitee.com/Marinc/springboot-demos/tree/master/springboot-email

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值