import * as plugins from './mailgun.plugins.js'; import * as interfaces from './interfaces/index.js'; export interface IMailgunAccountContructorOptions { apiToken: string; region: 'eu' | 'us'; } export class MailgunAccount { public apiBaseUrl: string; public options: IMailgunAccountContructorOptions; public smartSmtps: { [domain: string]: plugins.smartsmtp.Smartsmtp } = {}; constructor(optionsArg: IMailgunAccountContructorOptions) { this.options = optionsArg; this.apiBaseUrl = this.options.region === 'eu' ? 'https://api.eu.mailgun.net/v3' : 'https://api.mailgun.net/v3'; } /** * allows adding smtp credentials * Format: [domain]|[username]|[password] */ public async addSmtpCredentials(credentials: string) { const credentialArray = credentials.split('|'); if (credentialArray.length !== 3) { throw new Error('credentials are in the wrong format'); } this.smartSmtps[credentialArray[0]] = await plugins.smartsmtp.Smartsmtp.createSmartsmtpWithRelay({ smtpServer: 'smtp.eu.mailgun.org', smtpUser: credentialArray[1], smtpPassword: credentialArray[2], }); } public async getRequest(routeArg: string, binaryArg: boolean = false) { let requestUrl = routeArg; const needsBaseUrlPrefix = !routeArg.startsWith('https://'); if (needsBaseUrlPrefix) { requestUrl = `${this.apiBaseUrl}${routeArg}`; } console.log(requestUrl); const response = await plugins.smartrequest.SmartRequest.create() .url(requestUrl) .headers({ Authorization: `Basic ${plugins.smartstring.base64.encode(`api:${this.options.apiToken}`)}`, 'Content-Type': 'application/json', }) .options({ keepAlive: false }) .get(); return response; } public async postFormData( routeArg: string, formFields: plugins.smartrequest.FormField[], ) { const requestUrl = `${this.apiBaseUrl}${routeArg}`; console.log(requestUrl); const response = await plugins.smartrequest.SmartRequest.create() .url(requestUrl) .headers({ Authorization: `Basic ${plugins.smartstring.base64.encode( `api:${this.options.apiToken}`, )}`, }) .options({ keepAlive: false }) .formData(formFields) .post(); return response; } /** * sends a SmartMail */ public async sendSmartMail( smartmailArg: plugins.smartmail.Smartmail, toArg: string, dataArg = {}, ) { const domain = smartmailArg.options.from.split('@')[1].replace('>', ''); const formFields: plugins.smartrequest.FormField[] = [ { name: 'from', value: smartmailArg.options.from, }, { name: 'to', value: toArg, }, { name: 'subject', value: smartmailArg.getSubject(dataArg), }, { name: 'html', value: smartmailArg.getBody(dataArg), }, ]; console.log(smartmailArg.attachments); for (const attachment of smartmailArg.attachments) { formFields.push({ name: 'attachment', value: attachment.contentBuffer, filename: attachment.parsedPath.base, }); } if (smartmailArg.getBody(dataArg)) { console.log('All requirements for API met'); const response = await this.postFormData( `/${domain}/messages`, formFields, ); if (response.status === 200) { console.log( `Sent mail with subject ${smartmailArg.getSubject( dataArg, )} to ${toArg} using the mailgun API`, ); return await response.json(); } else { let errorMessage = `HTTP ${response.status}: ${response.statusText}`; try { // Get response body as text first const errorText = await response.text(); console.log(errorText); // Try to parse as JSON try { const errorBody = JSON.parse(errorText); errorMessage = errorBody.message || JSON.stringify(errorBody); } catch { // Not JSON, use plain text errorMessage = errorText || errorMessage; } } catch { // Couldn't read body at all } throw new Error(`could not send email: ${errorMessage}`); } } else { console.log( 'An empty body was provided. This does not work via the API, but using SMTP instead.', ); const wantedSmartsmtp = this.smartSmtps[domain]; if (!wantedSmartsmtp) { console.log('did not find appropriate smtp credentials'); return; } await wantedSmartsmtp.sendSmartMail(smartmailArg, toArg); console.log( `Sent mail with subject "${smartmailArg.getSubject( dataArg, )}" to "${toArg}" using an smtp transport over Mailgun.`, ); } } public async retrieveSmartMailFromMessageUrl(messageUrlArg: string) { console.log(`retrieving message for ${messageUrlArg}`); const response = await this.getRequest(messageUrlArg); if (response.status === 404) { const body: any = await response.json(); console.log(body.message); return null; } const responseBody: interfaces.IMailgunMessage = await response.json(); const smartmail = new plugins.smartmail.Smartmail({ from: responseBody.From, body: responseBody['body-html'], subject: responseBody.Subject, creationObjectRef: responseBody, }); // lets care about attachments if (responseBody.attachments && responseBody.attachments instanceof Array) { for (const attachmentInfo of responseBody.attachments) { const attachmentName = attachmentInfo.name; const attachmentContents = await this.getRequest( attachmentInfo.url, true, ); const arrayBuffer = await attachmentContents.arrayBuffer(); smartmail.addAttachment( new plugins.smartfile.SmartFile({ path: `./${attachmentName}`, base: `./${attachmentName}`, contentBuffer: Buffer.from(arrayBuffer), }), ); } } return smartmail; } public async retrieveSmartMailFromNotifyPayload(notifyPayloadArg: any) { return await this.retrieveSmartMailFromMessageUrl( notifyPayloadArg['message-url'], ); } }