NestJS 实现定时自动发送 Exchange 邮件

定时任务

NestJS 定时任务可通过miaowing/nest-schedule实现。

定时任务的实现

  1. 按照 miaowing/nest-schedule 的说明文档,将 nest-schedule 模块导入到项目中:
 import { Module } from '@nestjs/common';
 import { ScheduleModule } from 'nest-schedule';

 @Module({
   imports: [
     ScheduleModule.register(),
   ]
 })
 export class AppModule {
 }

2. 需要支持定时任务的服务继承 NestSchedule 类:

import { Injectable } from '@nestjs/common';
 import { Cron, Interval, Timeout, NestSchedule } from 'nest-schedule';

 @Injectable() // Only support SINGLETON scope
 export class ScheduleService extends NestSchedule {    
   @Cron('15 16 * * *')
   async cronJob() {
     console.log('executing cron job');
   }

3. 执行定时任务的方法添加@Cron('15 16 * * *')注解。这条注解的意思是“每天16:15” 执行一次定时任务。这里似乎与常见的 Cron 表达式不一样:第一个数据段代表的不是秒而是分,由此可见,miaowing/nest-schedule 不支持秒级的定时任务

以上三步就能实现定时任务的功能了。

需要留意的问题

  • 不知何故,开启服务后,定时任务并没有执行,必须手动访问过任意一个 controller 之后,定时任务才会开启。开始猜测是在子模块导入的原因,尝试在根模块注入之后,问题依旧,难道与Only support SINGLETON scope有关系?
  • @Cron('15 16 * * *')中的表达式并非常见的 Cron 表达式,第一个数据段代表的是而不是秒,且不支持如:“0/15 * * * *每15分钟执行一次”这样的配置,逗号分隔符是支持的,因此每15分钟执行一次可以配置成“0,15,30,45”。

发送 Exchange 邮件

Exchange 邮件的支持借助gautamsi/ews-javascript-api来实现。

Exchange 邮件发送实现

  1. 导入相关方法
import {
   ExchangeService, ExchangeVersion,
   Uri as ExchangeUri,
   WebCredentials, EmailMessage, MessageBody, ConfigurationApi
 } from 'ews-javascript-api';

2. 新建ExchangeService 服务

const exch = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

3. 配置登录凭据以及服务地址

exch.Credentials = new WebCredentials(ewsConfig.username, ewsConfig.password);
 exch.Url = new ExchangeUri(ewsConfig.host);

4. 构建要发送的邮件实体,Subject 为邮件的标题,Body 为邮件的内容,收件人地址可以通过msgattach.ToRecipients.Add(address)方法实现:

const msgattach = new EmailMessage(exch);

 msgattach.Subject = mailContent.Subject;
 msgattach.Body = new MessageBody(mailContent.Body);
 msgattach.ToRecipients.Add(address);

5. 发送邮件

 msgattach.SendAndSaveCopy() // 此方法返回 Promise

按照上述步骤实现,可能会出现鉴权不通过的问题,可能是 NTLM 认证的问题,NTLM 是 telnet 的一种验证身份的方式,是 Windows NT 早期版本的标准安全协议。可以安装另外一个库@ewsjs/xhr, 尝试以下配置:

...
import { XhrApi } from '@ewsjs/xhr';
...
const exch = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
const xhr = new XhrApi({ rejectUnauthorized: false }).useNtlmAuthentication(username, password);

ConfigurationApi.ConfigureXHR(xhr);

完整代码如下:

import {
  ExchangeService, ExchangeVersion,
  Uri as ExchangeUri,
  WebCredentials, EmailMessage, MessageBody, ConfigurationApi
} from 'ews-javascript-api';

/**
* 发邮件
*/
mailToSomeOne(address: string, mailContent: {
    Subject: string,
    Body: string
}): void {
    const exch = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
    const xhr = new XhrApi({ rejectUnauthorized: false }).useNtlmAuthentication(ewsConfig.username, ewsConfig.password);

    ConfigurationApi.ConfigureXHR(xhr);

    exch.Credentials = new WebCredentials(ewsConfig.username, ewsConfig.password);
    exch.Url = new ExchangeUri(ewsConfig.host);

    const msgattach = new EmailMessage(exch);

    msgattach.Subject = mailContent.Subject;
    msgattach.Body = new MessageBody(mailContent.Body);
    msgattach.ToRecipients.Add(address);

    msgattach.SendAndSaveCopy().then(res => {
      console.log(res);
    }, (err) => {
      console.error(err);
    });
}

需要留意的问题

  • 权限部分可能并非使用 NTLM 方式,@ewsjs/xhr还支持 Cookies Auth,可查阅文档。
15764854565097.jpg

评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注