node.js 基于 STMP 协议和 EWS 协议发送邮件

2022-04-15 0 1,094
目录
  • 1 基于 STMP 协议的 node.js 发送邮件方法
  • 2 基于 MS Exchange 邮件服务器的 node.js 发送邮件方法
    • 2.1 使用 node-ews 发送 MS Exchange 邮件
      • 2.1.1 封装一个基于 node-ews 发送邮件的方法
      • 2.1.2 基于 NTLMAuth 的认证配置方式
    • 2.2 使用 ews-javascript-api 发送 MS Exchange 邮件
    • 3 扩展参考

      本文主要介绍 node.js 发送基于 STMP 协议和 MS Exchange Web Service(EWS) 协议的邮件的方法。文中所有参考代码均以 TypeScript 编码示例。

      1 基于 STMP 协议的 node.js 发送邮件方法

      提到使用 node.js 发送邮件,基本都会提到大名鼎鼎的 Nodemailer 模块,它是当前使用 STMP 方式发送邮件的首选。
      基于 NodeMailer 发送 STMP 协议邮件的文章网上已非常多,官方文档介绍也比较详细,在此仅列举示例代码以供对比参考:
      封装一个 sendMail 邮件发送方法:

      /**
       * 使用 Nodemailer 发送 STMP 邮件
       * @param {Object} opts 邮件发送配置
       * @param {Object} smtpCfg smtp 服务器配置
       */
      async function sendMail(opts, smtpCfg) {
       const resultInfo = { code: 0, msg: '', result: null };
       if (!smtpCfg) {
       resultInfo.msg = '未配置邮件发送信息';
       resultInfo.code = - 1009;
       return resultInfo;
       }
      
       // 创建一个邮件对象
       const mailOpts = Object.assign(
       {
       // 发件人
       from: `Notify <${smtpCfg.auth.user}>`,
       // 主题
       subject: 'Notify',
       // text: opts.content,
       // html: opts.content,
       // 附件内容
       // /*attachments: [{
       // filename: 'data1.json',
       // path: path.resolve(__dirname, 'data1.json')
       // }, {
       // filename: 'pic01.jpg',
       // path: path.resolve(__dirname, 'pic01.jpg')
       // }, {
       // filename: 'test.txt',
       // path: path.resolve(__dirname, 'test.txt')
       // }],*/
       },
       opts
       );
      
       if (!mailOpts.to) mailOpts.to = [];
       if (!Array.isArray(mailOpts.to)) mailOpts.to = String(mailOpts.to).split(',');
       mailOpts.to = mailOpts.to.map(m => String(m).trim()).filter(m => m.includes('@'));
      
       if (!mailOpts.to.length) {
       resultInfo.msg = '未配置邮件接收者';
       resultInfo.code = - 1010;
       return resultInfo;
       }
      
       const mailToList = mailOpts.to;
       const transporter = nodemailer.createTransport(smtpCfg);
      
       // to 列表分开发送
       for (const to of mailToList) {
       mailOpts.to = to.trim();
       try {
       const info = await transporter.sendMail(mailOpts);
       console.log('mail sent to:', mailOpts.to, ' response:', info.response);
       resultInfo.msg = info.response;
       } catch (error) {
       console.log(error);
       resultInfo.code = -1001;
       resultInfo.msg = error;
       }
       }
      
       return resultInfo;
      }
      

      使用 sendMail 方法发送邮件:

      const opts = {
       subject: 'subject for test',
       /** HTML 格式邮件正文内容 */
       html: `email content for test: <a href="https://lzw.me" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" rel="external nofollow" >https://lzw.me</a>`,
       /** TEXT 文本格式邮件正文内容 */
       text: '',
       to: 'xxx@lzw.me',
       // 附件列表
       // attachments: [],
      };
      const smtpConfig = {
       host: 'smtp.qq.com', //QQ: smtp.qq.com; 网易: smtp.163.com
       port: 465, //端口号。QQ邮箱 465,网易邮箱 25
       secure: true,
       auth: {
       user: 'xxx@qq.com', //邮箱账号
       pass: '', //邮箱的授权码
       },
      };
      sendMail(opts, smtpConfig).then(result => console.log(result));
      

      2 基于 MS Exchange 邮件服务器的 node.js 发送邮件方法

      对于使用微软的 Microsoft Exchange Server 搭建的邮件服务,Nodemailer 就无能为力了。Exchange Web Service(EWS)提供了访问 Exchange 资源的接口,在微软官方文档中对其有详细的接口定义文档。针对 Exchange 邮件服务的流行第三方库主要有 node-ews 和 ews-javascript-api。

      2.1 使用 node-ews 发送 MS Exchange 邮件

      下面以 node-ews 模块为例,介绍使用 Exchange 邮件服务发送邮件的方法。

      2.1.1 封装一个基于 node-ews 发送邮件的方法

      封装一个 sendMailByNodeEws 方法:

      import EWS from 'node-ews';
      
      export interface IEwsSendOptions {
       auth: {
       user: string;
       pass?: string;
       /** 密码加密后的秘钥(NTLMAuth.nt_password)。为字符串时,应为 hex 编码结果 */
       nt_password?: string | Buffer;
       /** 密码加密后的秘钥(NTLMAuth.lm_password)。为字符串时,应为 hex 编码结果 */
       lm_password?: string | Buffer;
       };
       /** Exchange 地址 */
       host?: string;
       /** 邮件主题 */
       subject?: string;
       /** HTML 格式邮件正文内容 */
       html?: string;
       /** TEXT 文本格式邮件正文内容(优先级低于 html 参数) */
       text?: string;
       to?: string;
      }
      
      /**
       * 使用 Exchange(EWS) 发送邮件
       */
      export async function sendMailByNodeEws(options: IEwsSendOptions) {
       const resultInfo = { code: 0, msg: '', result: null };
      
       if (!options) {
       resultInfo.code = -1001;
       resultInfo.msg = 'Options can not be null';
       } else if (!options.auth) {
       resultInfo.code = -1002;
       resultInfo.msg = 'Options.auth{user,pass} can not be null';
       } else if (!options.auth.user || (!options.auth.pass && !options.auth.lm_password)) {
       resultInfo.code = -1003;
       resultInfo.msg = 'Options.auth.user or Options.auth.password can not be null';
       }
      
       if (resultInfo.code) return resultInfo;
      
       const ewsConfig = {
       username: options.auth.user,
       password: options.auth.pass,
       nt_password: options.auth.nt_password,
       lm_password: options.auth.lm_password,
       host: options.host,
       // auth: 'basic',
       };
      
       if (ewsConfig.nt_password && typeof ewsConfig.nt_password === 'string') {
       ewsConfig.nt_password = Buffer.from(ewsConfig.nt_password, 'hex');
       }
      
       if (ewsConfig.lm_password && typeof ewsConfig.lm_password === 'string') {
       ewsConfig.lm_password = Buffer.from(ewsConfig.lm_password, 'hex');
       }
      
       Object.keys(ewsConfig).forEach(key => {
       if (!ewsConfig[key]) delete ewsConfig[key];
       });
      
       // initialize node-ews
       const ews = new EWS(ewsConfig);
       // define ews api function
       const ewsFunction = 'CreateItem';
       // define ews api function args
       const ewsArgs = {
       attributes: {
        MessageDisposition: 'SendAndSaveCopy',
       },
       SavedItemFolderId: {
        DistinguishedFolderId: {
        attributes: {
         Id: 'sentitems',
        },
        },
       },
       Items: {
        Message: {
        ItemClass: 'IPM.Note',
        Subject: options.subject,
        Body: {
         attributes: {
         BodyType: options.html ? 'HTML' : 'Text',
         },
         $value: options.html || options.text,
        },
        ToRecipients: {
         Mailbox: {
         EmailAddress: options.to,
         },
        },
        IsRead: 'false',
        },
       },
       };
      
       try {
       const result = await ews.run(ewsFunction, ewsArgs);
       // console.log('mail sent to:', options.to, ' response:', result);
       resultInfo.result = result;
       if (result.ResponseMessages.MessageText) resultInfo.msg = result.ResponseMessages.MessageText;
       } catch (err) {
       console.log(err.stack);
       resultInfo.code = 1001;
       resultInfo.msg = err.stack;
       }
      
       return resultInfo;
      }
      

      使用 sendMailByNodeEws 方法发送邮件:

      sendMailByNodeEws({
       auth: {
       user: 'abc@xxx.com',
       pass: '123456',
       /** 密码加密后的秘钥(NTLMAuth.nt_password)。为字符串时,应为 hex 编码结果 */
       nt_password: '',
       /** 密码加密后的秘钥(NTLMAuth.lm_password)。为字符串时,应为 hex 编码结果 */
       lm_password: '',
       },
       /** Exchange 地址 */
       host: 'https://ews.xxx.com',
       /** 邮件主题 */
       subject: 'subject for test',
       /** HTML 格式邮件正文内容 */
       html: `email content for test: <a href="https://lzw.me" rel="external nofollow"  rel="external nofollow"  rel="external nofollow" rel="external nofollow" >https://lzw.me</a>`,
       /** TEXT 文本格式邮件正文内容(优先级低于 html 参数) */
       text: '',
       to: 'xxx@lzw.me',
      })
      

      2.1.2 基于 NTLMAuth 的认证配置方式

      直接配置 pass 密码可能会导致明文密码泄露,我们可以将 pass 字段留空,配置 nt_password 和 lm_password 字段,使用 NTLMAuth 认证模式。此二字段基于 pass 明文生成,其 nodejs 生成方式可借助 httpntlm 模块完成,具体参考如下:

      import { ntlm as NTLMAuth } from 'httpntlm';
      
      /** 将输入的邮箱账号密码转换为 NTLMAuth 秘钥(hex)格式并输出 */
      const getHashedPwd = () => {
       const passwordPlainText = process.argv.slice(2)[0];
      
       if (!passwordPlainText) {
       console.log('USEAGE: \n\tnode get-hashed-pwd.js [password]');
       return;
       }
      
       const nt_password = NTLMAuth.create_NT_hashed_password(passwordPlainText.trim());
       const lm_password = NTLMAuth.create_LM_hashed_password(passwordPlainText.trim());
      
       // console.log('\n password:', passwordPlainText);
       console.log(` nt_password:`, nt_password.toString('hex'));
       console.log(` lm_password:`, lm_password.toString('hex'));
      
       return {
       nt_password,
       lm_password,
       };
      };
      
      getHashedPwd();
      

      2.2 使用 ews-javascript-api 发送 MS Exchange 邮件

      基于 ews-javascript-api 发送邮件的方式,在其官方 wiki 有相关示例,但本人在测试过程中未能成功,具体为无法取得服务器认证,也未能查证具体原因,故以下代码仅作参考:

      /**
       * 使用 `ews-javascript-api` 发送(MS Exchange)邮件
       */
      export async function sendMailByEwsJApi(options: IEwsSendOptions) {
       const resultInfo = { code: 0, msg: '', result: null };
      
       if (!options) {
       resultInfo.code = -1001;
       resultInfo.msg = 'Options can not be null';
       } else if (!options.auth) {
       resultInfo.code = -1002;
       resultInfo.msg = 'Options.auth{user,pass} can not be null';
       } else if (!options.auth.user || (!options.auth.pass && !options.auth.lm_password)) {
       resultInfo.code = -1003;
       resultInfo.msg = 'Options.auth.user or Options.auth.password can not be null';
       }
      
       const ews = require('ews-javascript-api');
       const exch = new ews.ExchangeService(ews.ExchangeVersion.Exchange2010);
       exch.Credentials = new ews.WebCredentials(options.auth.user, options.auth.pass);
       exch.Url = new ews.Uri(options.host);
       ews.EwsLogging.DebugLogEnabled = true; // false to turnoff debugging.
      
       const msgattach = new ews.EmailMessage(exch);
       msgattach.Subject = options.subject;
       msgattach.Body = new ews.MessageBody(ews.BodyType.HTML, escape(options.html || options.text));
       if (!Array.isArray(options.to)) options.to = [options.to];
       options.to.forEach(to => msgattach.ToRecipients.Add(to));
       // msgattach.Importance = ews.Importance.High;
      
       // 发送附件
       // msgattach.Attachments.AddFileAttachment('filename to attach.txt', 'c29tZSB0ZXh0');
      
       try {
       const result = await msgattach.SendAndSaveCopy(); // .Send();
       console.log('DONE!', result);
       resultInfo.result = result;
       } catch (err) {
       console.log('ERROR:', err);
       resultInfo.code = 1001;
       resultInfo.msg = err;
       }
       return resultInfo;
      }
      

      3 扩展参考

      nodemailer.com/about/
      github.com/CumberlandG…
      github.com/gautamsi/ew…
      github.com/lzwme/node-…

      以上就是node.js 基于 STMP 协议和 EWS 协议发送邮件的详细内容,更多关于node.js 发送邮件的资料请关注NICE源码其它相关文章!

      免责声明:
      1、本网站所有发布的源码、软件和资料均为收集各大资源网站整理而来;仅限用于学习和研究目的,您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 不得使用于非法商业用途,不得违反国家法律。否则后果自负!

      2、本站信息来自网络,版权争议与本站无关。一切关于该资源商业行为与www.niceym.com无关。
      如果您喜欢该程序,请支持正版源码、软件,购买注册,得到更好的正版服务。
      如有侵犯你版权的,请邮件与我们联系处理(邮箱:skknet@qq.com),本站将立即改正。

      NICE源码网 JavaScript node.js 基于 STMP 协议和 EWS 协议发送邮件 https://www.niceym.com/31532.html