@tanayvk/mailer
Version:
@adonisjs/mail without @adonisjs/core dependency.
214 lines (211 loc) • 6.59 kB
JavaScript
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