Skip to content

Commit

Permalink
feat: Add ZeptoMail support (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
ashish-naik authored Oct 19, 2024
1 parent 9af92ae commit f211b99
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 6 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,38 @@ const server = new ParseServer({
});
```

### Example for ZeptoMail Service

This is an example for the ZeptoMail Service client using the ZeptoMail JavaScript SDK.
Provide comma separated email adddresses in recepient parameter to send to multiple.

```js
// Configure mail client
var { SendMailClient } = require('zeptomail');

const url = process.env.ZEPTOMAIL_URL;
const token = process.env.ZEPTOMAIL_TOKEN;
const zeptoMaiClient = new SendMailClient({ url, token });


// Configure Parse Server
const server = new ParseServer({
...otherServerOptions,

emailAdapter: {
module: 'parse-server-api-mail-adapter',
options: {
... otherAdapterOptions,

apiCallback: async ({ payload, locale }) => {
const zeptoMailPayload = ApiPayloadConverter.zeptomail({ api: '1.1', payload });
await zeptoMaiClient.sendMail(zeptoMailPayload);
},
}
}
});
```

## Custom API

This is an example of how the API payload can be adapted in the adapter configuration `apiCallback` according to a custom email provider's API specification.
Expand Down
48 changes: 48 additions & 0 deletions spec/ApiMailAdapter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,54 @@ describe('ApiMailAdapter', () => {
expect(payload.Message.Body.Text.Data).toBe(examplePayload.text);
expect(payload.Message.Body.Html.Data).toBe(examplePayload.html);
});

describe('convert ZeptoMail API v1.1 payload', () => {
it('converts single recipient payload', () => {
const payload = converter.zeptomail({ api: '1.1', payload: examplePayload});
expect(payload.from.address).toEqual(examplePayload.from);
expect(payload.to).toBeInstanceOf(Array);
expect(payload.to.length).toBe(1);
expect(payload.to[0].email_address.address).toEqual(examplePayload.to);
expect(payload.reply_to).toBeInstanceOf(Array);
expect(payload.reply_to.length).toBe(1);
expect(payload.reply_to[0].address).toEqual(examplePayload.replyTo);
expect(payload.subject).toBe(examplePayload.subject);
expect(payload.textbody).toBe(examplePayload.text);
expect(payload.htmlbody).toBe(examplePayload.html);
});

it('converts multiple recipients payload', () => {
const examplePayload = {
from: "from@example.com",
to: "to@example.com,toanother@example.com",
replyTo: "replyto@example.com, replytoanother@example.com",
subject: "ExampleSubject",
text: "ExampleText",
html: "ExampleHtml"
}
const payload = converter.zeptomail({ api: '1.1', payload: examplePayload});
expect(payload.from.address).toEqual(examplePayload.from);
expect(payload.to).toBeInstanceOf(Array);
const exmplePayloadToAddresses = examplePayload.to.split(',');
const toAddresses = payload.to.map(entry => entry.email_address.address);
exmplePayloadToAddresses.forEach((address, index) => {
expect(address).toBe(toAddresses[index]);
});
expect(payload.reply_to).toBeInstanceOf(Array);
const exmpleReplyToAddresses = examplePayload.replyTo.split(',').map(addr => addr.trim());
const replyToAddresses = payload.reply_to[0].address.split(',').map(addr => addr.trim());
exmpleReplyToAddresses.forEach((exampleAddress, index) => {
expect(replyToAddresses[index]).toBe(exampleAddress);
});
expect(payload.subject).toBe(examplePayload.subject);
expect(payload.textbody).toBe(examplePayload.text);
expect(payload.htmlbody).toBe(examplePayload.html);
});

it('throws if unsupported version', () => {
expect(() => converter.zeptomail({ api: 'invalidVersion', payload: examplePayload})).toThrowError(/invalidVersion/);
});
});
});

describe('invoke _sendMail', function () {
Expand Down
68 changes: 62 additions & 6 deletions src/ApiPayloadConverter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ class ApiPayloadConverter {

/**
* @description Converts the mail payload for the official Mailgun client.
* @param {Object} originalPayload The original payload (provider agnostic).
* @param {Object} data The original payload (provider agnostic).
* @returns {Object} The payload according to Mailgun client specification.
*/
static mailgun(originalPayload) {
static mailgun(data) {

// Clone payload
const payload = Object.assign({}, originalPayload);
const payload = Object.assign({}, data);

// Transform reply-to
if (payload.replyTo) {
Expand All @@ -25,13 +25,13 @@ class ApiPayloadConverter {

/**
* @description Converts the mail payload for the AWS Simple Mail Service (AWS JavaScript SDK v3).
* @param {Object} originalPayload The original payload (provider agnostic).
* @param {Object} data The original payload (provider agnostic).
* @returns {Object} The payload according to AWS SDK specification.
*/
static awsSes(originalPayload) {
static awsSes(data) {

// Clone payload
const payload = Object.assign({}, originalPayload);
const payload = Object.assign({}, data);

// Transform sender
payload.Source = [payload.from];
Expand Down Expand Up @@ -92,6 +92,62 @@ class ApiPayloadConverter {

return payload;
}

/**
* Converts the mail payload for the ZeptoMail.
* @param {Object} data The original payload
* @param {String} data.api The provider API version.
* @param {Object} data.payload The payload to convert to be compatible with the provider API.
* @returns {Object} The payload according to ZeptoMail SDK specification.
*/
static zeptomail(data) {

// Clone payload
const payload = Object.assign({}, data.payload);
switch (data.api) {
case '1.1': {

// Transform sender
payload.from = {
address: payload.from
}
const emailString = payload.to;
const emailAddresses = emailString.split(',').map(email => email.trim());
const formattedEmails = emailAddresses.map((address) => ({
email_address: {
address: address.trim()
}
}));
payload.to = formattedEmails;
if (payload.replyTo) {
payload.reply_to = [{
address: payload.replyTo
}
];
delete payload.replyTo;
}

// If message has content
if (payload.subject || payload.textbody || payload.htmlbody) {
if (payload.text || payload.html) {
payload.textbody = {};
if (payload.text) {
payload.textbody = payload.text;
delete payload.text;
}
if (payload.html) {
payload.htmlbody = payload.html;
delete payload.html;
}
}
}
break;
}
default:
throw new Error(`Unsupported ZeptoMail API version '${ data.api }'.`);
}
return payload;
}
}

module.exports = ApiPayloadConverter;

0 comments on commit f211b99

Please sign in to comment.