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) } }