Brian F爱
从专注于角图,Web技术以yobet英雄联盟及波特兰的Node.js的Google开发人员专家中学习。
Ad ·ultimatecourses.com.
用终极课程学习角度正确的方式

node.js + sendgrid + typescript

(Almost) Every application needs to send an email at some point. I'll walk through using ZURB's Foundation for Email to send great looking emails with the SendGrid API.

源代码

您可以在Github上沿源代码下载并遵循或叉叉以下内容:

Getting Started

我们将使用类型签字(TS) - 一个包含强大打字和伟大工具的javascript的超集。我们也将与节点包管理器(NPM)一起使用Node.js。

您需要安装节点,它配备了NPM。然后您可以安装类型:

$苏达NPM.安装-g typescript

接下来,为项目安装SendGrid Helper库(如果您愿意)。如果您没有创建一个项目,您需要运行NPM init.一个开始。

$NPM.安装发送grid --save

注意我附加--save标志,以便依赖于我们的依赖package.json文件。

目标

在我潜入之前,这里是我的目标:

  1. 写一个服务层以轻松地使用zurb发送HTML电子邮件电子邮件的基金会2项目(以前称为墨水)。
  2. Use the邮件由SendGrid库提供的辅助人。
  3. 该exposed API should be small and easy to use. I want to send a sweet email in a couple of lines of code with little ceremony.

电子邮件的基金会2

我将使用电子邮件的基金会2provided by ZURB. It provides a slick way to create email templates that will work in most major email clients. In other words, it takes the pain out of formatting nice looking email templates.

我会使用的SASS版本

首先,让我们安装Foundation CLI:

$苏达NPM.安装-g基础 -  CLI

接下来,为电子邮件项目创建新的基础:

$ foundation new --framework电子邮件

接下来,通过以下方式启动服务器:

$cd{项目}$NPM.开始

After starting the service your browser should open tohttp:// localhost:3000。该index lists all of the pre-built email templates that come with Foundations for Email. I suggest you pick one that you like, customize it, and remove the rest.

这是我使用的模板的屏幕镜头:

Email template screen shot

请注意,我在我的模板中定义了一些替换:

  • -名字-
  • -inviter-
  • -groupName-

这些是占位符,其中Sendgrid邮件助手将替代我们指定的值。

Finally, let's build our production-ready templates:

$NPM.运行建设

应用结构

Here is a snapshot of my application's structure:

├──dist├────外墙│├────────────────────────────────────────────│└──测试 - 电子邮件。

几件事要注意:

  • dist目录是我们打印的输出目录SRC.目录。这将由节点执行。但是,我们将专注于源代码。
  • 电子邮件目录包含电子邮件项目的基础Johnoneone.。我们将参考distdirectory when adding content to our emails using a template.
  • SRC.目录包含我们的打字应用程序源。我正在使用表现node.js的框架。
  • 在这内SRC.目录是A.服务目录,以及我有一个目录电子邮件服务。
  • 电子邮件服务文件是我们的模块EmailService.类。我们很快就会审查。
  • Factory.Ts.is a simple factory that will create email templates, such as theSendInviteEmailTemplate类。
  • 外墙directory contains a baseEmail类(在电子邮件中的模块中)以及生产尺度testemail.classes in生产电子邮件测试电子邮件
  • 模板sdirectory contains a base模板我们将定义的所有模板的抽象课程。现在我有一个名为的一个模板SendInviteEmailTemplate

类图

进一步模拟我的解决方案,我创建了一个UML类图。我用了staruml.要创建以下内容:

Email template screen shot

一些设计说明:

  • 摘要Emailclass represents an email and is a facade for the SendGrid mail helper. The生产尺度class will send the email as is. Thetestemail.class is used when testing, and will delete the邮件对象并创建一个被发送到的新一个发邮件地址。这是为了防止在测试时向客户发送电子邮件。
  • EmailTemplate.类代表模板。这是为了使用构建的电子邮件模板来使用Zurb Foundation。该计划是每个模板都是使用电子邮件的基础构建的,然后创建一个关联的类延伸EmailTemplate.。实现将为HTML模板提供文件名,并替换模板中的任何值。
  • EmailService.揭露Email在一个API中的立面,到我的其余部分。该EmailService.can send simple/text emails as well as work with anEmailTemplate.填充内容和主题。
  • EmailTemplingFateF.是一个有静态方法来获得模板的单身。

实施

Let's send off the invite email. This is as simple as:

进口{EmailTemplingFateF.}'./services/email/factory';模板=EmailTemplingFateF.邀请;模板名字=邀请名字;模板邀请者=`${用户名字}${用户}`;模板电子邮件添加(邀请电子邮件,`${邀请名字}${邀请}`trim());模板发送()然后(()=>{下一个();})抓住(下一个);

请注意,我在Express的REST API路由方法中使用它,这就是您看到的原因下一个()method being invoked when my promises is resolved or rejected.

花了一点点调整,但我真的很喜欢这个实现。它简单易用。只需从中获取模板EmailTemplingFateF.,设置替换值,收件人然后发送它。

Email

Email类代表使用SendGrid的邮件帮助程序发送的电子邮件,这反过来又使用其REST API。电子邮件是Sendgrid Mail Helper的立面。

//导入配置进口{ConfigurationFactory.}“../../../config/factory”;进口{IConfiguration}"../../../config/config";//导入sendgrid.进口*asSendGrid“sendgrid”;进口{SendgridContent.,sendgridemail.,SendGridMail,sendgridpersonalization,sendgridresponse.,sendgridsubstitution.}“../send-grid”;/ ** *电子邮件的基类。* @class电子邮件* /export抽象classEmail{//constants上市staticfrom_email.:="no-reply@johnoneone.com";上市static来自名字:=“约翰1:1”;上市static发邮件:=“blove@johnoneone.com”;上市static命名:=“yobet外围Brian Love”;// config.protected组态:IConfiguration;//the SendGrid APIprotected发送Grid:任何;// Sendgrid邮件助手protected_邮件:任何;/ ** * * @constructor * /构造函数(){//获取配置对象这个组态=ConfigurationFactory.config();//store the SendGrid API这个发送Grid=SendGrid(这个组态发送Grid);//从电子邮件地址设置默认值(ES)这个SetFromString.(Emailfrom_email.,Email来自名字);}/** * Returns the Contents array. * @method get contents * @return {SendGridContent[]} */上市得到内容():SendgridContent.[]{返回这个邮件GetContents.();}/ ** *返回从电子邮件对象。* @return {sendgridemail} * /上市得到():sendgridemail.{返回这个邮件从获得();}/ ** *设置从电子邮件和名称。* @method从* / @param {sendgridemail} from * /上市set(:sendgridemail.){这个邮件塞尔弗洛姆();}/** * Returns the populated SendGrid.mail.Email helper object. * @method get mail * @return {SendGridMail} */上市得到邮件():SendGridMail{//返回现有邮件对象if(这个_邮件!==未定义){返回这个_邮件;}//设置邮件助手这个_邮件=SendGrid邮件邮件();返回这个_邮件;}/** * Returns the SendGrid Personalization object. * @method get personalization * @return {SendGridPersonalization} */上市得到个性化():sendgridpersonalization{//验证个性化存在if(这个邮件GetPersonalizations.()===未定义||这个邮件GetPersonalizations.()length===0){这个邮件兼容性化(SendGrid邮件个性化());}//get first personalization by default个性化=这个邮件GetPersonalizations.();返回个性化[0];}/ ** *返回此电子邮件的主题。* @method get主题* @return {string} * /上市得到学科():{返回这个邮件gets赞许();}/** * Set the subject for this email. * @method set subject * @param {string} subject */上市set学科(学科:){这个邮件sitewject.(学科);}/ ** *退回替换。* @Method获得替换* @return {sendgridsubstitution []} * /上市得到替换():sendgridsubstitution.[]{返回这个个性化getsubstitutions.();}/ ** *将内容添加到此电子邮件中。* @Method AddContent * @param {sendgridcontent}内容* @return {eament} * /上市addContent.(content:SendgridContent.):Email{//将内容添加到邮件助手这个邮件addContent.(content);返回这个;}/ ** *从一个简单的字符串向此电子邮件添加内容。默认类型是“text / html”。* @Method AddContentString * @param {string} value * @param {string} type * @return {email} * /上市AddContentString.(:,类型:=“text / html”):Email{//构建内容content:SendgridContent.={类型:类型,:};//将内容添加到邮件助手这个addContent.(content);返回这个;}/** * Add to address using simple values. * @method addTo * @param {string} email * @param {string} name * @return {Email} */上市添加(电子邮件:,名称?:):Email{//创建电子邮件=SendGrid邮件Email(电子邮件);if(名称!==未定义){名称=名称;}//添加到邮件助手这个个性化添加();返回这个;}/ ** *在电子邮件模板中添加替换。* @method addsubstitution * @param {string} key * @param {string} value * @return {email} * /上市addsubstitut(:,:):Email{substition=SendGrid邮件Substitution(,);这个个性化addsubstitut(substition);返回这个;}/ ** *发后挂钩。* @method postsend * @abstract * /抽象post();/ ** *预先发送钩子。* @method presend * @abstract * /抽象pre();/ ** *发送电子邮件。* @method发送* @abstract * /抽象发送():Promise<sendgridresponse.>;/ ** *从使用简单值设置。* @method setFromString * @param {string} email * @param {string} name * @return {Email} */上市SetFromString.(电子邮件:,名称?:):Email{//创建电子邮件=SendGrid邮件Email(电子邮件);if(名称!==未定义){名称=名称;}//set from property这个=;返回这个;}}

有些笔记:

  • 我用A.ConfigurationFactory.存储API键进行应用程序。如果您愿意,您可以忽略此操作,并且仅在代码中的Sendgrid中的值。
  • from_email.来自名字static strings are the default values when sending an email. You can always override these. You will want to change this to match your needs.
  • 发邮件命名在测试模式下发送电子邮件时是否默认。
  • 内容存档器返回array of内容在电子邮件中。
  • 突变和配电器暴露于此Email目的。
  • 邮件存档器返回singletonSendGrid.mail.Mail实例。
  • 个性化存档器返回个性化目的。这是添加替换的辅助方法。
  • 学科utator和Accessor暴露主题串。
  • 替换accesor exposes the substitutions object. Note here that I have defined this as an array ofSubstitutionobjects. This does not appear to be the case and I have submitted a PR for the TypeScript definition file.
  • addContent.()方法使开发人员能够直接添加内容到电子邮件。
  • 一个名为的帮助方法AddContentString.允许您轻松地将HTML字符串内容添加到电子邮件中。
  • 添加()method adds a new recipient to the email.
  • addsubstitution()method adds a key/value pair for substituting values in your email template.
  • post()pre()methods are abstract and must be implemented in an extending class.
  • setfromstring()是一个辅助方法来设置fromEmail目的。

生产尺度testemail.

生产尺度testemail.课程扩展了摘要Email类。这些类在适当的情况下使用EmailService.

当我们测试时,我们不想向预定的收件人发送电子邮件。相反,我们将邮件发送到发邮件地址。

EmailTemplate.

EmailTemplate.class represents an email template that is generated using ZURB's Foundation for Emails (formerly Ink) project.

//导入电子邮件进口{Email}“../facades/email”;进口{EmailService.}“../email-service”;//导入文件系统I / O API进口{存在,readFileSync}“FS”;//导入sendgrid.进口{SendgridContent.,sendgridresponse.}“../send-grid”;/ ** *电子邮件模板。*模板由Zurb Foundation获取电子邮件生成。* @class EmailTemplate * /export抽象classEmailTemplate.{//电子邮件dist路径上市staticdist_path.:="email/johnoneone/dist";//the email上市电子邮件:Email;//电子邮件服务上市EmailService.:EmailService.;//电子邮件主题抽象主题:;// mime类型上市类型:=“text / html”;//the contents of the templateprivate_内容:SendgridContent.;//模板文件名private_文档名称:;/ ** * * @constructor * /构造函数(){//创建电子邮件服务的新实例这个EmailService.=EmailService.();//存储对电子邮件的引用这个电子邮件=这个EmailService.电子邮件;}/ ** *返回此模板的SendgridContent对象。* @method获取内容* @return {sendgridcontent} * /上市得到content():SendgridContent.{//如果已存在,则返回内容if(这个_内容!==未定义){返回这个_内容;}//调用预填充挂钩这个pre();//构建模板文件路径var.path:=`${EmailTemplate.dist_path.}/${这个文档名称}`;//验证模板文件存在if(!存在(path)){throw错误(`[EmailTemplate.Content]该文件不存在{路径:${path}}。`);}//读取文件=readFileSync(path)至String();//构建内容content:SendgridContent.={类型:这个类型,:};//调用内容后钩子这个post();返回content;}/ ** *返回此模板的dist_path目录中的文件名。* @method获取文件名* @return {string} * /上市得到文档名称():{返回这个_文档名称;}/ ** *将此模板的Dist_Path目录中的文件名设置为此模板。*此文件的内容将用于电子邮件内容。* @method设置filename * @param {string} filename * /上市set文档名称(文档名称:){if(!文档名称比赛(/\.html$/i)){文档名称+ =“.html”;}这个文档名称=文档名称;}/ ** *内容后钩子。* @method post * @abstract * /抽象post();/** * Pre-content hook. * @method pre * @abstract */抽象pre();/** * Send this email template using the EmailService. * @method send * @abstract */上市发送():Promise<sendgridresponse.>{返回这个EmailService.populatefromtemplate.(这个)发送();}}

让我解释摘要EmailTemplate.类:

  • 首先我导入必要的函数和类。请注意,我正在进口存在readFileSyncfunctions from the file system Node package.
  • 该static variabledist_path.is the relative path to thedistdirectory for my Foundation for Emails build directory.
  • 电子邮件EmailService.属性存储引用Email对象以及我们的EmailService.
  • 学科字符串属性是抽象的,必须在扩展类中定义。
  • 内容property is also abstract and must be implemented in an extending class.
  • 文档名称字符串属性也是抽象的。扩展课程将指导EmailTemplate.在我们使用的模板文件上。
  • post()pre()hooks are abstract and will be invoked before and after the content is generated from the template. Thepre()方法在生成内容之前,为我们提供了连接任何替换的机会。该post()方法为我们提供了解任何东西的机会。
  • 发送()method uses theEmailService.填充A.Email使用模板并发送它。

SendInviteEmailTemplate

SendInviteEmailTemplate班级是抽象的示例实现EmailTemplate.类:

//导入基本电子邮件类进口{EmailTemplate.}“。/模板”;/** * Invite email template. * @class SendInviteEmailTemplate */exportclassSendInviteEmailTemplate延伸EmailTemplate.{//被邀请的人的名字上市名字:="";// Inver的全名上市邀请者:="";/** * Returns the email subject. * @method get subject * @return {string} */上市得到学科():{返回`${这个邀请者}has invited you to John 1:1 - a social app for Christians in small groups`;}/ ** *返回此模板的dist_path目录中的文件名。* @method获取文件名* @return {string} * /上市得到文档名称():{返回"invite.html";}/ ** *内容后钩子。* @method post * /上市post(){//没做什么}/** * Pre-content hook. * @method pre */上市pre(){//add custom substitutions这个电子邮件addsubstitut(“-名字-”,这个名字);这个电子邮件addsubstitut("-inviter-",这个邀请者);}}

这一个更容易理解(希望):

  • 名字邀请者串properties contain the values that will be substituted into the email template. The developer using this class will set the value of these properties before sending the email.
  • 首先,我覆盖了访问者的学科property to return a custom subject for the email.
  • 其次,我覆盖了访问者文档名称属性返回模板文件名。
  • 最后,我实施了pre()post()钩子。该pre()方法将替换电线焊接。

EmailService.

EmailService.类使开发人员能够在不使用模板的情况下发送电子邮件,以及基于模板填充电子邮件。

//导入配置进口{ConfigurationFactory.}“../../config/factory”;进口{IConfiguration}“../../config/config”;//导入电子邮件进口{Email}"./facades/email";进口{testemail.}“./facades/test-email”;进口{生产尺度}“./facades/production-email”;//导入模板进口{EmailTemplate.}“./templates/template”;//导入sendgrid.进口{SendgridContent.,SendGridMail,sendgridresponse.}"./send-grid";/ ** *公开的电子邮件服务。* @class emailservice * /exportclassEmailService.{//the email上市电子邮件:Email;/ ** * * @constructor * /构造函数(){//获取配置组态=ConfigurationFactory.config();//根据配置设置电子邮件立面if(组态isProduction()){这个电子邮件=生产尺度();}else{这个电子邮件=testemail.();}}/ ** *返回此电子邮件的主题。* @method get主题* @return {string} * /上市得到学科():{返回这个电子邮件学科;}/** * Set the subject for this email. * @method set subject * @param {string} subject */上市set学科(学科:){这个电子邮件学科=学科;}/ ** *将内容添加到此电子邮件中。* @Method AddContent * @param {sendgridcontent}内容* @return {eament} * /上市addContent.(content:SendgridContent.):EmailService.{这个电子邮件addContent.(content);返回这个;}/ ** *从一个简单的字符串向此电子邮件添加内容。默认类型是“text / html”。* @param {string} value * @param {string} type * @return {email} * /上市AddContentString.(?:,类型:=“text / html”):EmailService.{这个电子邮件AddContentString.(,类型);返回这个;}/** * Add to address using simple values. * @method addTo * @param {string} email * @param {string} name * @return {Email} */上市添加(电子邮件:,名称?:):EmailService.{这个电子邮件添加(电子邮件,名称);返回这个;}/ ** *在电子邮件模板中添加替换。* @method addsubstitution * @param {string} key * @param {string} value * @return {email} * /上市addsubstitut(:,:):EmailService.{这个电子邮件addsubstitut(,);返回这个;}/ ** *使用模板填充电子邮件。* @method populate fromptemplate * /上市populatefromtemplate.(模板:EmailTemplate.):EmailService.{//从模板添加内容到电子邮件这个电子邮件addContent.(模板content);//从模板中设置主题这个电子邮件学科=模板学科;返回这个;}/ ** *发送电子邮件。* @method发送* @abstract * /上市发送():Promise<sendgridresponse.>{返回这个电子邮件发送();}/ ** *从使用简单值设置。* @method setfromstring * @param {string}电子邮件* @param {string} name * @return {emailservice} * /上市SetFromString.(电子邮件:,名称?:):EmailService.{这个电子邮件SetFromString.(电子邮件,名称);返回这个;}}

有些笔记:

  • 同样,我正在使用一个配置对象来确定我的应用程序是否正在生产或测试模式下运行。这是基于环境变量。
  • 电子邮件property is either a生产尺度或者testemail.目的。这是在我的构造函数()function.
  • 几个属性和方法Email班级暴露在EmailService., 包含学科,添加(),addsubstitution()setfromstring()
  • populatefromtemplate()method accepts anEmailTemplate.object and populate theEmailcontent and subject from it.
  • 发送()方法调用邮件助手发送()方法,返回Promise目的。

测试

我使用莫克,柴和柴Mocha-TypeScript.。You can run the test via:

$NPM.test

结论

在构建此时,我必须复制很多Sendgrid接口node_modules/sendgrid/index.d.tsdefinition file as most of them are not publicly accessible. I created asend-grid.d.ts.包含我需要的所有定义的文件。

As always, please feel free to contribute or to comment your suggestions!

Download

您可以在github上下载源代码或fork存储库:

Brian F爱

嗨,我是布莱恩。我对类型名称,Angular和node.js感兴趣我嫁给了我最好的朋友邦妮,我住在波特兰和我滑雪(很多)。