Giter Site home page Giter Site logo

timing-email-node's Introduction

前言

前阵子在一个技术群里,看见某位大佬说写了个程序每天定时给女朋友发电子邮件,突然想到,我也可以写这样一个程序每天给女朋友定时发纪念日提醒及天气提醒,于是查阅相关资料并且向那个大佬要了他写的程序源码,在空余时间,我自己也动手实践了一下。

实现过程

前提知识储备

  • node 相关知识
  • axios 库的使用
  • nodemailer 库的使用
  • Promise 知识
  • window 开启定时执行脚本任务

结构目录

├── config.js         #项目配置
├── daily-email.js    #代码程序文件
├── public            #后期会把每天生成的数据放到一个josn文件或者excel表中查看
├── template.html     #测试生成模板页面使用
├── timing-task.bat   #定时执行程序bat

编写静态页面

image.png

<style>
    .container {
      background-color: rgb(165, 115, 140);
      background: url("http://cn.bing.com/th?id=OHR.GreatTits_ZH-CN0546267922_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp") center no-repeat;
      background-size: 100%;
      width: 960px;
      height: 540px;
      display: flex;
      justify-content: space-between;
      flex-direction: column;
      align-items: center;
      color: white;
    }

    .title {
      font-size: 22px;
      margin-top: 50px;
    }

    .description {
      color: white;
    }

    .content {
      background: rgba(255, 255, 255, 0.5);
      margin: 0 auto;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      padding: 20px;
      box-sizing: border-box;
    }

    .content>p {
      text-align: left;
      font-size: 12px;
      color: white;
      width: 100%;
      margin: 5px auto;
      padding: 0;
    }
  </style>


<div class="container">
    <div class="title">陪你一起看世界:第1162期</div>
    <a class="description" target="_blank" href="https://www.bing.com/search?q=%E5%A4%A7%E5%B1%B1%E9%9B%80&amp;form=hpcapt&amp;mkt=zh-cn" rel="noopener">冬天树枝上的大山雀,法国 (© Eric Ferry/Alamy)</a>
    <div class="content">
      <p style="display: flex;">
        <span>😘今天是:<span style="border-bottom: 1px dashed rgb(204, 204, 204); --darkreader-inline-border-bottom:#3e4446;" t="5" times="" data-darkreader-inline-border-bottom="">2022/2/18</span>,星期五,是我们在一起的第: 1162天~🥰🎈🎈🎈,今天天气: 多云 最高温 18℃,最低温 10℃,今天的风向是:东风。❤❤❤
        </span>
      </p>
      <p></p>
      <p>I love three things in this world.
        Sun,Moon and You.
        Sun for morning,Moon for night,
        and You forever.</p>
    </div>
  </div>

获取每日的 bing 壁纸

const fetchBingPictrue = async () => {
  const BPicList = await axios.get("https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1")
  let bingInfo = {}
  if (!BPicList.images[0]) {
    console.error("获取bing壁纸失败")
    return bingInfo
  }
  bingInfo.picUrl = `http://cn.bing.com${BPicList.images[0].url}`
  bingInfo.copyright = BPicList.images[0].copyright
  bingInfo.copyrightlink = BPicList.images[0].copyrightlink
  console.log('🚀【获取到的bing壁纸信息】', bingInfo);
  return bingInfo
}

获取天气信息

const fetchWeaterByCity = async () => {
  let weather = await axios.get(
    `http://wthrcdn.etouch.cn/weather_mini?city=广州`,
  );
  if (weather.data.forecast.length === 0) {
    console.error("获取今日天气失败")
    return {}
  }
  console.log('🚀【获取到天气信息】', weather.data.forecast[0]);
  return weather.data.forecast[0]
}

获取每日一句土味情话

const fetchSentence = async () => {
  const sentence = await axios.get(`https://chp.shadiao.app/api.php`);
  console.log('🚀【获取到每日一句】', sentence);
  return sentence
}

获取到数据到生成HTML

/**
 * @description: 设置email的内容
 * @return {*}
 * @param {*} bingInfo bing的信息,包含图片及文字描述和链接
 * @param {*} weatherInfo 今天天气信息
 * @param {*} sentence 每日一句土味情话
 */
const setEmailContent = (bingInfo, weatherInfo, sentence) => {
  const today = new Date().toLocaleDateString();  //获取今天的日期
  const weekday = new Date().toLocaleString("default", { weekday: "long" }) // 获取今天是星期几
  const dayCount = parseInt((new Date() - new Date('2000-01-01') / 1000 / 60 / 60 / 24)  // 获取是第几天
  const content = `
        <style>
        .container {
            background-color: rgb(165, 115, 140);
            background: url("${bingInfo.picUrl}") center no-repeat;
            background-size: 100%;
            width: 960px;
            height: 540px;
            display: flex;
            justify-content: space-between;
            flex-direction: column;
            align-items: center;
            color: white;
        }
        .title {
            font-size: 22px;
            margin-top: 50px;
        }
        .description {
            color: white;
        }
        .content {
            background: rgba(255, 255, 255, 0.5);
            margin: 0 auto;
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            padding: 20px;
            box-sizing: border-box;
        }
        .content>p {
            text-align: left;
            font-size: 12px;
            color: white;
            width: 100%;
            margin: 5px auto;
            padding: 0;
        }
        </style>
        <div class="container">
            <div class="title">陪你一起看世界:第${dayCount}期</div>
            <a class="description" target="_blank" href="${bingInfo.copyrightlink}">${bingInfo.copyright}</a>
            <div class="content">
                <p style="display: flex;">
                    <span>😘今天是:${today}${weekday},是我们在一起的第: ${dayCount}天~🥰🎈🎈🎈,今天天气:  ${weatherInfo.type}${weatherInfo.high},最${
     weatherInfo.low},今天的风向是:${weatherInfo.fengxiang}。❤❤❤
                    </span>
                </p>
                <p></p>
                <p>${sentence}</p>
            </div>
        </div>
  `;
  return content
}

使用 nodemailer 发送电子邮件

参考文章:https://segmentfault.com/a/1190000012251328

/**
 * @description: 通过Nodemailer发送电子邮件
 * @return {*}
 * @param {*} content 邮件内容
 */
const sendEmailByNodemailer = (content) => {
  const transporter = nodemailer.createTransport({
    service: '163', // 使用了内置传输发送邮件 查看支持列表:https://nodemailer.com/smtp/well-known/
    port: 465, // SMTP 端口
    secureConnection: true, // 使用了 SSL
    auth: {
      user: '[email protected]', //邮箱账号
      pass: 'xxxyyyxxxyyzxzxz', // 不是邮箱密码,是你设置的smtp授权码
    },
  });

  let mailOptions = {
    from: `"邮箱名称" <邮箱地址>`, // 发送者 邮件地址
    to: `"邮件标题" <要发送人的邮箱>`, // 逗号隔开的接收人列表
    subject: `想和你一起看世界:第${parseInt(
        (new Date() - new Date('2000-01-01') / 1000 / 60 / 60 / 24,
      )}`, // 邮件标题
    // 发送text或者html格式
    // text: 'Hello world?', // plain text body
    // 发送的html内容
    html: content,
  };

  // send mail with defined transport object
  transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
      return console.log("error", error);
    }
    console.log("Message sent: %s", info.messageId);
    console.log(info);
  });
}

执行发送邮件操作

const handleSendEmail = async () => {
  try {
    const bingInfo = await fetchBingPictrue()
    const weatherInfo = await fetchWeaterByCity()
    const sentence = await fetchSentence()
    const emailContent = setEmailContent(bingInfo, weatherInfo, sentence)
    sendEmailByNodemailer(emailContent)
  } catch (error) {
    // 这里可以catch 相关错误后,将错误信息发送到邮箱通知查看
    console.error("发送信息失败")
  }
}

实现效果

image.png

优化-将项目相关配置整合到配置文件中

// config.js
// 配置相关信息
exports.config = {
  CITY: '深圳',  //获取城市天气
  TOGETHER_TIME: '2000-01-01', //在一起的时间
  EMAIL_NAME: '陪你一起看世界系列', //邮箱名称
  EMALI_SERVICE: '163', //使用163服务 https://nodemailer.com/smtp/well-known/
  EMAIL_ACCOUNT: '[email protected]', //使用发送邮箱的账号
  EMAIL_PASS:  'xxxyyyxxxyyzxzxz', // 不是邮箱密码,是你设置的smtp授权码
  TO_EMAIL: '[email protected]', // 接送者邮箱
  TO_TITLE: '你的专属', //标题
} 

编写 DOS 命令

//  timing-task.bat
//  bat 批处理文件是一个文本文件,这个文件的每一行都是一条DOS命令(大部分时候就好象我们在DOS提示符下执行的命令行一样),你可以使用DOS下的Edit或者Windows的记事本(notepad)等任何文本文件编辑工具创建和修改批处理文件

node D:/node/daily-email.js   //这里写项目执行文件的位置

如何定时执行该程序

  • 第一种方式,使用云函数的方式,设置定时执行程序;
  • 第二种方式,购买轻量级服务器的方式,利用服务器实现定时执行该程序;
  • 第三种方式,将自己的电脑变成服务器(如果你的电脑长期不关机的话),或者当程序设置开机自动执行,每天开机时自动执行脚本发送邮件。

window系统定时执行 bat 文件

进入系统任务计划程序

image.png

创建基本任务

image.png

创建基本任务名称和描述

image.png

选择触发器并设置执行时间

image.png image.png

启动程序,选择 bat 文件地址

image.png

查看定时任务是否设置成功

image.png

将生成的数据保存到json文件中

const fs = require("fs")
const path = require('path')
const dataFilePath = path.resolve(__dirname, './public/data.json')

/**
 * @description: 写入数据到json文件中
 * @return {*}
 * @param {*} data 需要写入的obj数据
 */
const writeData = (data) => {
  try {
    const oldFileData = fs.readFileSync(dataFilePath, 'UTF-8').toString()
    const oldData = JSON.parse(oldFileData)
    oldData.push(data)
    fs.writeFileSync(dataFilePath, JSON.stringify(oldData))
  } catch (err) {
    console.log('🚀【写入数据出现错误】', err);
  }
}

遇到的问题

手机微信预览QQ邮箱邮件,背景图没显示

image.png

  • 原因:有些HTML的电子邮件客户端没有按照 W3C 规范一致的地呈现网页,所有导致渲染出来会不一致,如部分标签不支持,CSS 存在兼容问题,且对 <head> 标签中写 style支持度不是那么好,js 无法使用或者不支持嵌入视频和音频。
  • 解决办法:使用内联样式写 CSS,了解常用邮箱 CSS 兼容性的相关知识,查阅文档。

使用 163 邮箱发送邮件到 QQ 邮箱中,背景图无法显示,会提示不是腾讯公司的官方邮件

image.png

  • 解决办法,双方都使用 QQ 邮箱,且是 QQ 好友可以避免第二种问题,能够正常显示内容,目前第一种问题暂时没有想到好的解决办法。

总结

  • 利用碎片化的学习积累,将实现过程、碰到的问题以及相应的解决方案记录下来,相信日积月累的知识沉淀,可以帮助自己更好更快的掌握编程技术,在工作中能更好的实现业务,也能很好的扩展自己的知识广度。
  • 相关源码:https://github.com/sean-lgt/timing-email-node
  • 以上就是本文的全部内容,希望这篇文章对你有所帮助,欢迎点赞和收藏,如果发现有什么错误或者更好的解决方案及建议,欢迎随时联系。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.