node.js 基于 STMP 協(xié)議和 EWS 協(xié)議發(fā)送郵件
本文主要介紹 node.js 發(fā)送基于 STMP
協(xié)議和 MS Exchange Web Service(EWS)
協(xié)議的郵件的方法。文中所有參考代碼均以 TypeScript 編碼示例。
1 基于 STMP 協(xié)議的 node.js 發(fā)送郵件方法
提到使用 node.js 發(fā)送郵件,基本都會(huì)提到大名鼎鼎的 Nodemailer
模塊,它是當(dāng)前使用 STMP 方式發(fā)送郵件的首選。
基于 NodeMailer
發(fā)送 STMP 協(xié)議郵件的文章網(wǎng)上已非常多,官方文檔介紹也比較詳細(xì),在此僅列舉示例代碼以供對(duì)比參考:
封裝一個(gè) sendMail
郵件發(fā)送方法:
/** * 使用 Nodemailer 發(fā)送 STMP 郵件 * @param {Object} opts 郵件發(fā)送配置 * @param {Object} smtpCfg smtp 服務(wù)器配置 */ async function sendMail(opts, smtpCfg) { const resultInfo = { code: 0, msg: '', result: null }; if (!smtpCfg) { resultInfo.msg = '未配置郵件發(fā)送信息'; resultInfo.code = - 1009; return resultInfo; } // 創(chuàng)建一個(gè)郵件對(duì)象 const mailOpts = Object.assign( { // 發(fā)件人 from: `Notify <${smtpCfg.auth.user}>`, // 主題 subject: 'Notify', // text: opts.content, // html: opts.content, // 附件內(nèi)容 // /*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 列表分開發(fā)送 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 方法發(fā)送郵件:
const opts = { subject: 'subject for test', /** HTML 格式郵件正文內(nèi)容 */ html: `email content for test: <a rel="external nofollow" rel="external nofollow" >https://lzw.me</a>`, /** TEXT 文本格式郵件正文內(nèi)容 */ text: '', to: 'xxx@lzw.me', // 附件列表 // attachments: [], }; const smtpConfig = { host: 'smtp.qq.com', //QQ: smtp.qq.com; 網(wǎng)易: smtp.163.com port: 465, //端口號(hào)。QQ郵箱 465,網(wǎng)易郵箱 25 secure: true, auth: { user: 'xxx@qq.com', //郵箱賬號(hào) pass: '', //郵箱的授權(quán)碼 }, }; sendMail(opts, smtpConfig).then(result => console.log(result));
2 基于 MS Exchange 郵件服務(wù)器的 node.js 發(fā)送郵件方法
對(duì)于使用微軟的 Microsoft Exchange Server 搭建的郵件服務(wù),Nodemailer 就無(wú)能為力了。Exchange Web Service(EWS)提供了訪問 Exchange 資源的接口,在微軟官方文檔中對(duì)其有詳細(xì)的接口定義文檔。針對(duì) Exchange 郵件服務(wù)的流行第三方庫(kù)主要有 node-ews 和 ews-javascript-api。
2.1 使用 node-ews 發(fā)送 MS Exchange 郵件
下面以 node-ews 模塊為例,介紹使用 Exchange 郵件服務(wù)發(fā)送郵件的方法。
2.1.1 封裝一個(gè)基于 node-ews 發(fā)送郵件的方法
封裝一個(gè) sendMailByNodeEws 方法:
import EWS from 'node-ews'; export interface IEwsSendOptions { auth: { user: string; pass?: string; /** 密碼加密后的秘鑰(NTLMAuth.nt_password)。為字符串時(shí),應(yīng)為 hex 編碼結(jié)果 */ nt_password?: string | Buffer; /** 密碼加密后的秘鑰(NTLMAuth.lm_password)。為字符串時(shí),應(yīng)為 hex 編碼結(jié)果 */ lm_password?: string | Buffer; }; /** Exchange 地址 */ host?: string; /** 郵件主題 */ subject?: string; /** HTML 格式郵件正文內(nèi)容 */ html?: string; /** TEXT 文本格式郵件正文內(nèi)容(優(yōu)先級(jí)低于 html 參數(shù)) */ text?: string; to?: string; } /** * 使用 Exchange(EWS) 發(fā)送郵件 */ 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 方法發(fā)送郵件:
sendMailByNodeEws({ auth: { user: 'abc@xxx.com', pass: '123456', /** 密碼加密后的秘鑰(NTLMAuth.nt_password)。為字符串時(shí),應(yīng)為 hex 編碼結(jié)果 */ nt_password: '', /** 密碼加密后的秘鑰(NTLMAuth.lm_password)。為字符串時(shí),應(yīng)為 hex 編碼結(jié)果 */ lm_password: '', }, /** Exchange 地址 */ host: 'https://ews.xxx.com', /** 郵件主題 */ subject: 'subject for test', /** HTML 格式郵件正文內(nèi)容 */ html: `email content for test: <a rel="external nofollow" rel="external nofollow" >https://lzw.me</a>`, /** TEXT 文本格式郵件正文內(nèi)容(優(yōu)先級(jí)低于 html 參數(shù)) */ text: '', to: 'xxx@lzw.me', })
2.1.2 基于 NTLMAuth 的認(rèn)證配置方式
直接配置 pass 密碼可能會(huì)導(dǎo)致明文密碼泄露,我們可以將 pass 字段留空,配置 nt_password 和 lm_password 字段,使用 NTLMAuth 認(rèn)證模式。此二字段基于 pass 明文生成,其 nodejs 生成方式可借助 httpntlm 模塊完成,具體參考如下:
import { ntlm as NTLMAuth } from 'httpntlm'; /** 將輸入的郵箱賬號(hào)密碼轉(zhuǎn)換為 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 發(fā)送 MS Exchange 郵件
基于 ews-javascript-api 發(fā)送郵件的方式,在其官方 wiki 有相關(guān)示例,但本人在測(cè)試過程中未能成功,具體為無(wú)法取得服務(wù)器認(rèn)證,也未能查證具體原因,故以下代碼僅作參考:
/** * 使用 `ews-javascript-api` 發(fā)送(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; // 發(fā)送附件 // 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 擴(kuò)展參考
nodemailer.com/about/
github.com/CumberlandG…
github.com/gautamsi/ew…
github.com/lzwme/node-…
以上就是node.js 基于 STMP 協(xié)議和 EWS 協(xié)議發(fā)送郵件的詳細(xì)內(nèi)容,更多關(guān)于node.js 發(fā)送郵件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 深入淺析Node.js單線程模型
- 搞懂什么是Node.js原來(lái)這么簡(jiǎn)單
- node.js 全局變量的具體使用
- node.js利用express自動(dòng)搭建項(xiàng)目的全過程
- node.js安裝及HbuilderX配置詳解
- node.js文件的復(fù)制、創(chuàng)建文件夾等相關(guān)操作
- Node.js中的異步生成器與異步迭代詳解
- 詳解node.js創(chuàng)建一個(gè)web服務(wù)器(Server)的詳細(xì)步驟
- Node.js 中如何收集和解析命令行參數(shù)
- 詳解阿里Node.js技術(shù)文檔之process模塊學(xué)習(xí)指南
- 利用node.js開發(fā)cli的完整步驟
- node.js通過Sequelize 連接MySQL的方法
- CentOS 8.2服務(wù)器上安裝最新版Node.js的方法
- Node.js文本文件BOM頭的去除方法
- appium+python自動(dòng)化配置(adk、jdk、node.js)
- 如何將Node.js中的回調(diào)轉(zhuǎn)換為Promise
- Node.js path模塊,獲取文件后綴名操作
- node.js爬蟲框架node-crawler初體驗(yàn)
- Nodejs探秘之深入理解單線程實(shí)現(xiàn)高并發(fā)原理
相關(guān)文章
nodejs對(duì)項(xiàng)目下所有空文件夾創(chuàng)建gitkeep的方法
這篇文章主要介紹了nodejs對(duì)項(xiàng)目下所有空文件夾創(chuàng)建gitkeep的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08node.js中的fs.writeFile方法使用說(shuō)明
這篇文章主要介紹了node.js中的fs.writeFile方法使用說(shuō)明,本文介紹了fs.writeFile的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12詳解如何在Node.js中執(zhí)行CPU密集型任務(wù)
Node.js通常被認(rèn)為不適合CPU密集型應(yīng)用程序,Node.js的工作原理使其在處理I/O密集型任務(wù)時(shí)大放異彩,雖然執(zhí)行CPU密集型任務(wù)肯定不是Node的主要使用場(chǎng)景,但是我們依舊有方法來(lái)改善這些問題,本文詳細(xì)給大家介紹了如何在Node.js中執(zhí)行CPU密集型任務(wù)2023-12-12nest.js,egg.js,midway,express,koa的區(qū)別小結(jié)
本文主要介紹了nest.js,egg.js,midway,express,koa的區(qū)別小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05Node.js開發(fā)教程之基于OnceIO框架實(shí)現(xiàn)文件上傳和驗(yàn)證功能
這篇文章主要介紹了Node.js開發(fā)教程之基于OnceIO框架實(shí)現(xiàn)文件上傳和驗(yàn)證的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11Mongoose經(jīng)常返回e11000 error的原因分析
這篇文章主要給大家分析了Mongoose經(jīng)常返回e11000 error的原因,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友可以們下面來(lái)一起看看吧。2017-03-03深入理解Node.js中通用基礎(chǔ)設(shè)計(jì)模式
大家在談到設(shè)計(jì)模式時(shí)最先想到的就是 singletons, observers(觀察者) 或 factories(工廠方法)。本文重點(diǎn)給大家介紹Node.JS一些基礎(chǔ)模式的實(shí)現(xiàn)方法,感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2017-09-09