UNPKG

@tanayvk/mailer

Version:

@adonisjs/mail without @adonisjs/core dependency.

214 lines (211 loc) 6.59 kB
import { E_MAIL_TRANSPORT_ERROR } from "../../chunk-3EFD4MAA.js"; import { debug_default } from "../../chunk-ZF2M7BIF.js"; import { MailResponse } from "../../chunk-CRXUSCKP.js"; import { __name } from "../../chunk-XE4OXN2W.js"; // src/transports/mailgun.ts import { ofetch } from "ofetch"; import { FormData, File } from "formdata-node"; import { ObjectBuilder } from "@poppinss/utils"; import { createTransport } from "nodemailer"; // src/utils.ts function streamToBlob(stream, mimeType) { return new Promise((resolve, reject) => { const chunks = []; stream.on("data", (chunk) => chunks.push(chunk)).once("end", () => resolve(new Blob(chunks, { type: mimeType }))).once("error", reject); }); } __name(streamToBlob, "streamToBlob"); // src/transports/mailgun.ts var NodeMailerTransport = class NodeMailerTransport2 { static { __name(this, "NodeMailerTransport"); } name = "mailgun"; version = "1.0.0"; #config; constructor(config) { this.#config = config; } /** * Converts a boolean flag to a yes/no string. */ #flagToYesNo(value) { if (value === void 0) { return; } return value === true ? "yes" : "no"; } /** * Returns pre-configured otags */ #getOTags(config) { const tags = new ObjectBuilder({}); tags.add("o:tag", config.oTags); tags.add("o:dkim", this.#flagToYesNo(config.oDkim)); tags.add("o:testmode", this.#flagToYesNo(config.oTestMode)); tags.add("o:tracking", this.#flagToYesNo(config.oTracking)); tags.add("o:tracking-clicks", this.#flagToYesNo(config.oTrackingClick)); tags.add("o:tracking-opens", this.#flagToYesNo(config.oTrackingOpens)); return tags.toObject(); } /** * Returns base url for sending emails */ #getBaseUrl() { return this.#config.domain ? `${this.#config.baseUrl.replace(/\/$/, "")}/${this.#config.domain}` : this.#config.baseUrl.replace(/\/$/, ""); } /** * Returns an object of custom headers */ #getHeaders(config) { const headers = config.headers || {}; return Object.keys(headers).reduce((result, key) => { result[`h:${key}`] = headers[key]; return result; }, {}); } /** * Returns an object of custom variables */ #getVariables(config) { const variables = config.variables || {}; return Object.keys(variables).reduce((result, key) => { result[`v:${key}`] = variables[key]; return result; }, {}); } /** * Formats an array of recipients to a string accepted by mailgun */ #formatRecipients(recipients) { if (!recipients) { return; } if (typeof recipients === "string") { return recipients; } if (Array.isArray(recipients)) { return recipients.map((recipient) => { if (typeof recipient === "string") { return recipient; } return `${recipient.name} <${recipient.address}>`; }).join(","); } return `${recipients.name} <${recipients.address}>`; } /** * Returns an object of `to`, `cc` and `bcc` */ #getRecipients(mail) { const recipients = new ObjectBuilder({}); recipients.add("to", this.#formatRecipients(mail.data.to)); recipients.add("cc", this.#formatRecipients(mail.data.cc)); recipients.add("bcc", this.#formatRecipients(mail.data.bcc)); return recipients.toObject(); } /** * If we call formData.append('to', ['a', 'b', 'c']), it will * create a single key-value pair with key 'to' and value 'a,b,c' * * This method will append each value separately */ #appendValue(form, key, value) { if (Array.isArray(value)) { value.forEach((item) => form.append(key, item)); } else { form.append(key, value); } } /** * Create FormData object to send to Mailgun */ async #createFormData(mail) { const tags = this.#getOTags(this.#config); const headers = this.#getHeaders(this.#config); const variables = this.#getVariables(this.#config); const recipients = this.#getRecipients(mail); const mimeMessage = await streamToBlob(mail.message.createReadStream(), "message/rfc822"); const mime = new File([ mimeMessage ], "messages.mime"); debug_default("mailgun mail mime %O", mimeMessage); debug_default("mailgun mail tags %O", tags); debug_default("mailgun mail headers %O", headers); debug_default("mailgun mail variables %O", variables); debug_default("mailgun mail recipients %O", recipients); const form = new FormData(); form.append("message", mime, "message.mime"); Object.keys(tags).forEach((key) => this.#appendValue(form, key, tags[key])); Object.keys(headers).forEach((key) => this.#appendValue(form, key, headers[key])); Object.keys(variables).forEach((key) => this.#appendValue(form, key, variables[key])); Object.keys(recipients).forEach((key) => this.#appendValue(form, "to", recipients[key])); return form; } /** * Sends email using Mailgun's HTTP API */ async send(mail, callback) { const envelope = mail.message.getEnvelope(); const url = `${this.#getBaseUrl()}/messages.mime`; const form = await this.#createFormData(mail); debug_default("mailgun mail url %s", url); debug_default("mailgun mail envelope %s", envelope); try { const encodedCredentials = Buffer.from(`api:${this.#config.key}`).toString("base64"); const response = await ofetch(url, { method: "POST", headers: { authorization: `Basic ${encodedCredentials}` }, body: form }); const mailgunMessageId = response.id; const messageId = mailgunMessageId ? mailgunMessageId.replace(/^<|>$/g, "") : mail.message.messageId(); callback(null, { id: mailgunMessageId, messageId, envelope }); } catch (error) { callback(new E_MAIL_TRANSPORT_ERROR("Unable to send email using the mailgun transport", { cause: error }), void 0); } } }; var MailgunTransport = class { static { __name(this, "MailgunTransport"); } #config; constructor(config) { this.#config = config; } /** * Sends message using the transport */ async send(message, config) { const mailgunTransport = new NodeMailerTransport({ ...this.#config, ...config }); const transporter = createTransport(mailgunTransport); const mailgunResponse = await transporter.sendMail(message); return new MailResponse(mailgunResponse.messageId, mailgunResponse.envelope, mailgunResponse); } }; export { MailgunTransport }; //# sourceMappingURL=mailgun.js.map