Created
October 4, 2022 14:28
-
-
Save voidnerd/8818b25e05efa0255e8f5d89beac1200 to your computer and use it in GitHub Desktop.
Typescript Mail Service (SMTP, Mailgun)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import nodemailer from 'nodemailer' | |
import ViewService from './view' // https://gist.github.com/ndiecodes/6e964e716a2b5b2aa22438912da2b3f3 | |
import Mailgun from 'mailgun.js' | |
import FormData from 'form-data' | |
import { MailgunMessageData } from 'mailgun.js/interfaces/Messages' | |
interface LooseObject { | |
[key: string]: any | |
} | |
interface Attachment { | |
filename: string | |
content?: Buffer | |
} | |
interface _Attachment { | |
filename: string | |
content?: Buffer | |
data?: Buffer | |
} | |
/** Start Mail Helper | |
* MailDrivers: smtp, mailgun | |
*/ | |
export default class Mail { | |
public SUBJECT!: string | |
public FROM: string | null = process.env.MAIL_FROM_ADDRESS || null | |
public DATA: LooseObject | null = null | |
public TO: string | undefined = '' | |
public CC: string | undefined = undefined | |
public BCC: string | undefined = undefined | |
public ATTACHMENTS: _Attachment[] = [] | |
public TEXT: string | undefined = undefined | |
public TEMPLATE!: string | |
/** | |
* | |
* @param {String} subject | |
* @returns {Mail} | |
*/ | |
subject(subject: string) { | |
this.SUBJECT = subject | |
return this | |
} | |
/** | |
* | |
* @param {String|Array} from | |
* @returns {Mail} | |
*/ | |
from(from: string) { | |
this.FROM = from | |
return this | |
} | |
/** | |
* | |
* @param {String|Array} to | |
* @returns {Mail} | |
*/ | |
to(to: string) { | |
this.TO = to | |
return this | |
} | |
/** | |
* | |
* @param {String|Array} cc | |
* @returns {Mail} | |
*/ | |
cc(cc: string) { | |
this.CC = cc | |
return this | |
} | |
/** | |
* | |
* @param {String|Array} bcc | |
* @returns {Mail} | |
*/ | |
bcc(bcc: string) { | |
this.BCC = bcc | |
return this | |
} | |
/** | |
* Attach Single File using Buffer | |
* @param {Array} attachments | |
* @returns {Mail} | |
*/ | |
attachFile(attachment: Attachment) { | |
if (process.env.MAIL_DRIVER === 'mailgun') { | |
this._attachMailgunFile(attachment) | |
} else { | |
this.ATTACHMENTS.push(attachment) | |
} | |
return this | |
} | |
/** | |
* Format attachment object for mailgun API | |
* @param attachment | |
* @returns | |
*/ | |
private _attachMailgunFile(attachment: Attachment) { | |
return this.ATTACHMENTS.push({ | |
filename: attachment.filename, | |
data: attachment.content, | |
}) | |
} | |
/** | |
* Attach multiple files | |
* @param attachments | |
* @returns | |
*/ | |
attachFiles(attachments: Attachment[]) { | |
if (process.env.MAIL_DRIVER === 'mailgun') { | |
this._attachMailgunFiles(attachments) | |
} else { | |
this.ATTACHMENTS = attachments | |
} | |
return this | |
} | |
/** | |
* Format attachment array for mailgun API | |
* @param attachment | |
* @returns | |
*/ | |
private _attachMailgunFiles(attachments: Attachment[]): _Attachment[] { | |
this.ATTACHMENTS = attachments.map((attachment) => { | |
return { | |
filename: attachment.filename, | |
data: attachment.content, | |
} | |
}) | |
return this.ATTACHMENTS | |
} | |
/** | |
* | |
* @param {String|Array} template | |
* @returns {Mail} | |
*/ | |
template(template: string) { | |
this.TEMPLATE = template | |
return this | |
} | |
/** | |
* | |
* @param {String} text | |
* @returns {Mail} | |
*/ | |
text(text: string | undefined) { | |
this.TEXT = text | |
return this | |
} | |
/** | |
* This object(data) will be passed the email view/renderer | |
* @param {Object} data | |
* @returns {Mail} | |
*/ | |
data(data: LooseObject) { | |
this.DATA = data | |
return this | |
} | |
/** Validate mail driver message params */ | |
validate() { | |
if (!this.SUBJECT) { | |
throw new Error('Subject Required!') | |
} | |
if (!this.FROM) { | |
throw new Error('From Address Required!') | |
} | |
if (!this.TO) { | |
throw new Error('TO Address Required!') | |
} | |
if (!this.TEMPLATE) { | |
throw new Error('Path to Template File Required!') | |
} | |
} | |
private async mailThroughSMTP(messageParams: MailgunMessageData) { | |
const smtp = nodemailer.createTransport({ | |
host: process.env.MAIL_HOST, | |
port: Number(process.env.MAIL_PORT), | |
secure: false, | |
auth: { | |
user: process.env.MAIL_USERNAME, | |
pass: process.env.MAIL_PASSWORD, | |
}, | |
}) | |
return smtp.sendMail(messageParams) | |
} | |
private async mailThroughMailgun(messageParams: MailgunMessageData) { | |
const mailgun = new Mailgun(FormData) | |
const mg = mailgun.client({ | |
username: 'api', | |
key: process.env.MAILGUN_API_KEY || '', | |
}) | |
return mg.messages.create( | |
process.env.MAILGUN_DOMAIN || '', | |
messageParams | |
) | |
} | |
/** | |
* | |
* @returns {Promise} | |
*/ | |
async send() { | |
this.validate() | |
const html = await new ViewService(this.TEMPLATE, this.DATA).getHtml() | |
const mailOptions: MailgunMessageData = { | |
from: `"${process.env.MAIL_FROM_NAME}" <${this.FROM}>`, | |
to: this.TO, | |
subject: this.SUBJECT, | |
cc: this.CC, | |
bcc: this.BCC, | |
attachments: this.ATTACHMENTS, | |
text: this.TEXT, | |
html: html, | |
} | |
if (process.env.MAIL_DRIVER === 'mailgun') { | |
return this.mailThroughMailgun(mailOptions) | |
} | |
return this.mailThroughSMTP(mailOptions) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment