Browse Source

:tada: able to send email message now

Song 4 years ago
parent
commit
63e8bd8744
10 changed files with 125 additions and 11 deletions
  1. 51 0
      common/email.js
  2. 7 2
      common/message.js
  3. 4 0
      common/token.js
  4. 10 0
      common/utils.js
  5. 6 0
      models/user.js
  6. 1 0
      package.json
  7. 6 0
      routers/index.js
  8. 0 6
      routers/message.js
  9. 1 0
      routers/user.js
  10. 39 3
      views/configure.ejs

+ 51 - 0
common/email.js

@@ -0,0 +1,51 @@
+const nodemailer = require('nodemailer');
+const { tokenStore } = require('./token');
+const config = require('../config');
+const { md2html } = require('./utils');
+
+async function pushEmailMessage(userPrefix, message) {
+  let user = tokenStore.get(userPrefix);
+  if (!user) {
+    return {
+      success: false,
+      message: `不存在的前缀:${userPrefix},请注意大小写`,
+    };
+  }
+
+  let transporter = nodemailer.createTransport({
+    host: user.smtpServer,
+    secure: true,
+    auth: {
+      user: user.smtpUser,
+      pass: user.smtpPass,
+    },
+  });
+
+  let targetEmail = user.email;
+  if (message.email) {
+    targetEmail = message.email;
+  }
+  try {
+    await transporter.sendMail({
+      from: `"消息推送服务" <${user.smtpUser}>`,
+      to: targetEmail,
+      subject: message.description,
+      text: message.content,
+      html: md2html(message.content),
+    });
+    return {
+      success: true,
+      message: 'ok',
+    };
+  } catch (e) {
+    console.error(e);
+    return {
+      success: false,
+      message: e.message,
+    };
+  }
+}
+
+module.exports = {
+  pushEmailMessage,
+};

+ 7 - 2
common/message.js

@@ -1,8 +1,13 @@
 const { pushWeChatMessage } = require('./wechat');
+const { pushEmailMessage } = require('./email');
 const Message = require('../models/message').Message;
 
 async function processMessage(userPrefix, message) {
-  if (message.content) {
+  if (message.email) {
+    // If message has the attribute "email", override its type.
+    message.type = '1';
+  }
+  if (message.content && message.type === '0') {
     message = await Message.create(message);
   }
   let result = {
@@ -14,7 +19,7 @@ async function processMessage(userPrefix, message) {
       result = await pushWeChatMessage(userPrefix, message);
       break;
     case '1': // Email message
-      // TODO: Email message
+      result = await pushEmailMessage(userPrefix, message);
       break;
     case '2': // HTTP GET request
       // TODO: HTTP GET request

+ 4 - 0
common/token.js

@@ -13,6 +13,10 @@ async function initializeTokenStore() {
         wechatOpenId: user.wechatOpenId,
         wechatVerifyToken: user.wechatVerifyToken,
         token: '',
+        email: user.email,
+        smtpServer: user.smtpServer,
+        smtpUser: user.smtpUser,
+        smtpPass: user.smtpPass,
       });
     }
   });

+ 10 - 0
common/utils.js

@@ -0,0 +1,10 @@
+const lexer = require('marked').lexer;
+const parser = require('marked').parser;
+
+function md2html(markdown) {
+  return parser(lexer(markdown));
+}
+
+module.exports = {
+  md2html,
+};

+ 6 - 0
models/user.js

@@ -42,6 +42,12 @@ User.init(
     wechatTemplateId: DataTypes.STRING,
     wechatOpenId: DataTypes.STRING,
     wechatVerifyToken: DataTypes.STRING,
+    smtpServer: {
+      type: DataTypes.STRING,
+      defaultValue: 'smtp.qq.com',
+    },
+    smtpUser: DataTypes.STRING,
+    smtpPass: DataTypes.STRING,
   },
   { sequelize }
 );

+ 1 - 0
package.json

@@ -18,6 +18,7 @@
     "express-session": "^1.17.1",
     "marked": "^1.2.7",
     "morgan": "~1.9.1",
+    "nodemailer": "^6.4.17",
     "sequelize": "^6.3.5",
     "serve-static": "^1.14.1",
     "sqlite3": "^5.0.1"

+ 6 - 0
routers/index.js

@@ -112,6 +112,9 @@ router.post('/configure', userRequired, async (req, res, next) => {
     wechatTemplateId: req.body.wechatTemplateId,
     wechatOpenId: req.body.wechatOpenId,
     wechatVerifyToken: req.body.wechatVerifyToken,
+    smtpServer: req.body.smtpServer,
+    smtpUser: req.body.smtpUser,
+    smtpPass: req.body.smtpPass,
   };
   for (let field in user) {
     let value = user[field];
@@ -140,6 +143,9 @@ router.post('/configure', userRequired, async (req, res, next) => {
       wechatOpenId: userObj.wechatOpenId,
       wechatVerifyToken: userObj.wechatVerifyToken,
       token: await requestToken(userObj.wechatAppId, userObj.wechatAppSecret),
+      smtpServer: userObj.smtpServer,
+      smtpUser: userObj.smtpUser,
+      smtpPass: userObj.smtpPass,
     });
     message = '配置更新成功';
     console.debug(tokenStore);

+ 0 - 6
routers/message.js

@@ -1,13 +1,7 @@
 const express = require('express');
-const lexer = require('marked').lexer;
-const parser = require('marked').parser;
 
 const router = express.Router();
 
-function md2html(markdown) {
-  return parser(lexer(markdown));
-}
-
 router.get('/delete/:id', (req, res, next) => {
   // TODO: delete message
   res.json({

+ 1 - 0
routers/user.js

@@ -38,6 +38,7 @@ router.all('/:userPrefix', async (req, res, next) => {
     title: req.query.title || req.body.title || '无标题',
     description: req.query.description || req.body.description,
     content: req.query.content || req.body.content,
+    email: req.query.email || req.body.email,
   };
   let result = await processMessage(userPrefix, message);
   res.json(result);

+ 39 - 3
views/configure.ejs

@@ -89,14 +89,50 @@
             </div>
 
             <div class="field">
-                <label class="label">邮箱</label>
+                <label class="label">默认目标邮箱</label>
                 <article class="message">
                     <div class="message-body">
-                        后续版本将支持选择将消息发送到邮箱
+                        要用 QQ 邮箱或者 Foxmail 邮箱,否则将无法通过微信得到邮件消息提醒
                     </div>
                 </article>
                 <div class="control">
-                    <input class="input" name="email" value="<%- email %>" type="text" placeholder="请输入你的邮箱(可不填)">
+                    <input class="input" name="email" value="<%- email %>" type="email" placeholder="请输入你的邮箱(可不填)">
+                </div>
+            </div>
+
+            <div class="field">
+                <label class="label">SMTP 服务器地址</label>
+                <article class="message">
+                    <div class="message-body">
+                        此项可选,但如果不配置该项,则无法发送邮件类型的消息
+                    </div>
+                </article>
+                <div class="control">
+                    <input class="input" name="smtpServer" value="<%- smtpServer %>" type="text" placeholder="如 smtp.qq.com">
+                </div>
+            </div>
+
+            <div class="field">
+                <label class="label">SMTP 账号</label>
+                <article class="message">
+                    <div class="message-body">
+                        此项可选,但如果不配置该项,则无法发送邮件类型的消息
+                    </div>
+                </article>
+                <div class="control">
+                    <input class="input" name="smtpUser" value="<%- smtpUser %>" type="email" placeholder="请输入 SMTP 账号(是一个邮箱地址)">
+                </div>
+            </div>
+
+            <div class="field">
+                <label class="label">SMTP 凭据</label>
+                <article class="message">
+                    <div class="message-body">
+                        此项可选,但如果不配置该项,则无法发送邮件类型的消息
+                    </div>
+                </article>
+                <div class="control">
+                    <input class="input" name="smtpPass" type="text" placeholder="请输入 SMTP Token">
                 </div>
             </div>