import nodemailer from "npm:nodemailer";
function containsValidHTML(input: string): boolean {
const htmlTagPattern = /<\/?[a-z][\s\S]*>/i;
return htmlTagPattern.test(input);
}
type Carrier =
| "tmobile"
| "verizon"
| "at&t"
| "cricket"
| "boost"
| "googlefi"
| "metro";
export class Mailer {
private transporter: ReturnType<typeof nodemailer.createTransport>;
constructor(
public readonly senderEmail: string,
public readonly senderPassword: string
) {
this.transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: senderEmail,
pass: senderPassword,
},
});
}
async sendEmail({
message,
recipient,
subject,
attachmentUrls,
}: {
recipient: string;
subject: string;
message: string;
attachmentUrls?: {
url: string;
filename: string;
}[];
}) {
let isHtml = false;
if (containsValidHTML(message)) {
isHtml = true;
}
const subjectBody = isHtml ? { html: message } : { text: message };
const mailOptions = {
from: this.senderEmail,
to: recipient,
subject: subject,
...subjectBody,
};
try {
const attachments = (() => {
const u =
attachmentUrls?.map((info) => ({
path: info.url,
filename: info.filename,
})) || [];
return [...u];
})();
const info = await this.transporter.sendMail({
...mailOptions,
attachments,
});
console.log("Email sent: " + info.response);
} catch (error) {
console.error("Error sending email:", error);
}
}
private getCarrierGateway(carrier: Carrier) {
const carrierToGateway: Record<Carrier, string> = {
tmobile: "tmomail.net",
verizon: "vtext.com",
"at&t": "txt.att.net",
cricket: "sms.cricketwireless.net",
boost: "myboostmobile.com",
googlefi: "msg.fi.google.com",
metro: "mymetropcs.com",
};
return carrierToGateway[carrier];
}
async sendSMS(
phoneNumber: string,
subject: string,
message: string,
options?: {
carrier?: Carrier;
}
) {
if (!phoneNumber.match(/^\d{10}$/)) {
throw new Error("Invalid phone number, must be 10 digits");
}
const carrier: Carrier = options?.carrier ?? "tmobile";
const tMobileGateway = `${phoneNumber}@${this.getCarrierGateway(carrier)}`;
const mailOptions = {
from: this.senderEmail,
to: tMobileGateway,
subject: subject,
text: message,
};
try {
const info = await this.transporter.sendMail(mailOptions);
console.log("Message sent:", info.response);
} catch (error) {
console.error("Error sending message:", error);
}
}
}