? ? 在年前摸魚的時(shí)候, 想著怎么把天氣等信息定時(shí)發(fā)送到我的郵箱, 讓我每天早上起床能準(zhǔn)時(shí)收到今天天氣, 同時(shí)我也想讓關(guān)心的人同樣收到, 于是整理了一下思路:
需求一: 開通SMTP服務(wù);
需求二: 天氣信息獲取;?
需求三:?批量發(fā)送郵件功能;
需求四: 定時(shí)發(fā)送;
我這里使用的egg框架, 因?yàn)楹?jiǎn)單好用, 接下來(lái)就開始一步一步實(shí)現(xiàn)
快速創(chuàng)建一個(gè)egg項(xiàng)目, 我使用的官方推薦:
我們推薦直接使用腳手架,只需幾條簡(jiǎn)單指令,即可快速生成項(xiàng)目(npm >=6.1.0), 框架默認(rèn)啟動(dòng)端口7001
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
啟動(dòng)項(xiàng)目:
$ npm run dev
$ open http://localhost:7001
一.開通SMTP服務(wù)
我這里用的是qq郵箱
具體流程我就不多說(shuō), 可參考【SMTP服務(wù)】開啟郵箱smtp服務(wù)教程
二. 天氣信息的獲取
去高德開放平臺(tái)免費(fèi)注冊(cè)一個(gè)開發(fā)者, 創(chuàng)建應(yīng)用, 申請(qǐng)key, 然后就擁有了很多api接口權(quán)限, 這里我使用的是v3接口高德開放平臺(tái)https://lbs.amap.com/
因?yàn)楸救四壳霸谏钲? 所以就直接在高德拿到了城市的代碼: 440300; 其他地區(qū)請(qǐng)通過高德接口自行獲取;
獲取天氣信息接口為:?https://restapi.amap.com/v3/weather/weatherInfo
參數(shù): key和city? ? ? ? 完整請(qǐng)求路徑: https://restapi.amap.com/v3/weather/weatherInfo?key=你的key&city=440300
具體返回內(nèi)容請(qǐng)以高德為準(zhǔn).
三.?批量發(fā)送郵件功能;
需要用到 nodemailer 插件和 smtpTransport 方法來(lái)實(shí)現(xiàn)批量郵件發(fā)送, 我這里將主要代碼放在了 業(yè)務(wù)邏輯層 Service目錄, 創(chuàng)建weather.js
const Service = require('egg').Service;
const nodemailer = require('nodemailer')
const smtpTransport = require('nodemailer-smtp-transport');
class WeatherService extends Service {
? ? async send(data) {
? ? ? ? const transporter = nodemailer.createTransport(smtpTransport({
? ? ? ? ? ? host: 'smtp.qq.com', //郵件服務(wù)供應(yīng)商
? ? ? ? ? ? pool: true,
? ? ? ? ? ? port: 465,
? ? ? ? ? ? secure: true, // use TLS使用HTTPS port可以是 465 也可以是 994
? ? ? ? ? ? auth: {
? ? ? ? ? ? ? ? user: 'xxx@qq.com', //發(fā)送方
? ? ? ? ? ? ? ? pass: 'xxx'//密碼或授權(quán)碼
? ? ? ? ? ? }
? ? ? ? }));
? ? ? ? // 發(fā)送給誰(shuí)以及發(fā)送內(nèi)容
? ? ? ? const mailOptions = {
? ? ? ? ? ? from: 'xxx@qq.com',//發(fā)送方
? ? ? ? ? ? to: '123456789@qq.com,987654321@qq.com',//接收方
? ? ? ? ? ? subject: '請(qǐng)注意查收天氣信息!', // 標(biāo)題
? ? ? ? ? ? html: `<div>
? ? ? ? ? ? <h1>今日天氣</h1>
? ? ? ? ? ? <p>省份: ${data.province}</p>
? ? ? ? ? ? <p>城市: ${data.city}</p>
? ? ? ? ? ? <p>溫度: ${data.temperature}°C</p>
? ? ? ? ? ? <p>天氣: ${data.weather}</p>
? ? ? ? ? ? <p>風(fēng)向: ${data.winddirection}</p>
? ? ? ? ? ? <p>風(fēng)力: ${data.windpower}級(jí)</p>
? ? ? ? ? ? <p>濕度: ${data.humidity}RH</p>
? ? ? ? ? ? <p>天氣時(shí)間: ${data.reporttime}</p>
? ? ? ? </div>`
? ? ? ? }
? ? ? ? async function sendEmails(transporter,mailOptions) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? const verifypass = await transporter.verify();//驗(yàn)證郵件發(fā)送者transporter是否配置正確
? ? ? ? ? ? ? ? const sendSucess = await transporter.sendMail(mailOptions);//配置無(wú)誤,發(fā)送發(fā)送郵件
? ? ? ? ? ? ? ? if (sendSucess) {
? ? ? ? ? ? ? ? ? ? console.log('發(fā)送成功');
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } catch (error) {
? ? ? ? ? ? ? console.log(error); ?
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? sendEmails(transporter,mailOptions);
? ? }
}
module.exports = WeatherService;
通過router輸出一個(gè)api可測(cè)試是否發(fā)送成功
四.?定時(shí)發(fā)送
這里用到了egg自帶的插件schedule, 在schedule目錄創(chuàng)建update_cache.js; 想要了解更多請(qǐng)參考?egg定時(shí)任務(wù)
主要邏輯就是定時(shí)執(zhí)行 從高德獲取到的天氣信息, 然后批量發(fā)送郵件
const Subscription = require('egg').Subscription;
class UpdateCache extends Subscription {
? // 通過 schedule 屬性來(lái)設(shè)置定時(shí)任務(wù)的執(zhí)行間隔等配置
? static get schedule() {
? ? return {
? ? ? cron: '0 0 8 * * *',
? ? ? type: 'all', // 指定所有的 worker 都需要執(zhí)行
? ? };
? }
? // subscribe 是真正定時(shí)任務(wù)執(zhí)行時(shí)被運(yùn)行的函數(shù)
? async subscribe() {
? ? const res = await this.ctx.curl('https://restapi.amap.com/v3/weather/weatherInfo?key=你的key&city=440300', {
? ? ? dataType: 'json',
? ? });
? ? if(res){
? ? ? const data = res.data.lives[0] || {}
? ? ? const info = await this.ctx.service.weather.send(data);
? ? ? console.log('發(fā)送成功',info);
? ? }
? }
}
module.exports = UpdateCache;
