Skip to content

Commit f211b99

Browse files
authored
feat: Add ZeptoMail support (#98)
1 parent 9af92ae commit f211b99

File tree

3 files changed

+142
-6
lines changed

3 files changed

+142
-6
lines changed

README.md

+32
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,38 @@ const server = new ParseServer({
323323
});
324324
```
325325

326+
### Example for ZeptoMail Service
327+
328+
This is an example for the ZeptoMail Service client using the ZeptoMail JavaScript SDK.
329+
Provide comma separated email adddresses in recepient parameter to send to multiple.
330+
331+
```js
332+
// Configure mail client
333+
var { SendMailClient } = require('zeptomail');
334+
335+
const url = process.env.ZEPTOMAIL_URL;
336+
const token = process.env.ZEPTOMAIL_TOKEN;
337+
const zeptoMaiClient = new SendMailClient({ url, token });
338+
339+
340+
// Configure Parse Server
341+
const server = new ParseServer({
342+
...otherServerOptions,
343+
344+
emailAdapter: {
345+
module: 'parse-server-api-mail-adapter',
346+
options: {
347+
... otherAdapterOptions,
348+
349+
apiCallback: async ({ payload, locale }) => {
350+
const zeptoMailPayload = ApiPayloadConverter.zeptomail({ api: '1.1', payload });
351+
await zeptoMaiClient.sendMail(zeptoMailPayload);
352+
},
353+
}
354+
}
355+
});
356+
```
357+
326358
## Custom API
327359

328360
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.

spec/ApiMailAdapter.spec.js

+48
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,54 @@ describe('ApiMailAdapter', () => {
402402
expect(payload.Message.Body.Text.Data).toBe(examplePayload.text);
403403
expect(payload.Message.Body.Html.Data).toBe(examplePayload.html);
404404
});
405+
406+
describe('convert ZeptoMail API v1.1 payload', () => {
407+
it('converts single recipient payload', () => {
408+
const payload = converter.zeptomail({ api: '1.1', payload: examplePayload});
409+
expect(payload.from.address).toEqual(examplePayload.from);
410+
expect(payload.to).toBeInstanceOf(Array);
411+
expect(payload.to.length).toBe(1);
412+
expect(payload.to[0].email_address.address).toEqual(examplePayload.to);
413+
expect(payload.reply_to).toBeInstanceOf(Array);
414+
expect(payload.reply_to.length).toBe(1);
415+
expect(payload.reply_to[0].address).toEqual(examplePayload.replyTo);
416+
expect(payload.subject).toBe(examplePayload.subject);
417+
expect(payload.textbody).toBe(examplePayload.text);
418+
expect(payload.htmlbody).toBe(examplePayload.html);
419+
});
420+
421+
it('converts multiple recipients payload', () => {
422+
const examplePayload = {
423+
424+
425+
426+
subject: "ExampleSubject",
427+
text: "ExampleText",
428+
html: "ExampleHtml"
429+
}
430+
const payload = converter.zeptomail({ api: '1.1', payload: examplePayload});
431+
expect(payload.from.address).toEqual(examplePayload.from);
432+
expect(payload.to).toBeInstanceOf(Array);
433+
const exmplePayloadToAddresses = examplePayload.to.split(',');
434+
const toAddresses = payload.to.map(entry => entry.email_address.address);
435+
exmplePayloadToAddresses.forEach((address, index) => {
436+
expect(address).toBe(toAddresses[index]);
437+
});
438+
expect(payload.reply_to).toBeInstanceOf(Array);
439+
const exmpleReplyToAddresses = examplePayload.replyTo.split(',').map(addr => addr.trim());
440+
const replyToAddresses = payload.reply_to[0].address.split(',').map(addr => addr.trim());
441+
exmpleReplyToAddresses.forEach((exampleAddress, index) => {
442+
expect(replyToAddresses[index]).toBe(exampleAddress);
443+
});
444+
expect(payload.subject).toBe(examplePayload.subject);
445+
expect(payload.textbody).toBe(examplePayload.text);
446+
expect(payload.htmlbody).toBe(examplePayload.html);
447+
});
448+
449+
it('throws if unsupported version', () => {
450+
expect(() => converter.zeptomail({ api: 'invalidVersion', payload: examplePayload})).toThrowError(/invalidVersion/);
451+
});
452+
});
405453
});
406454

407455
describe('invoke _sendMail', function () {

src/ApiPayloadConverter.js

+62-6
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ class ApiPayloadConverter {
66

77
/**
88
* @description Converts the mail payload for the official Mailgun client.
9-
* @param {Object} originalPayload The original payload (provider agnostic).
9+
* @param {Object} data The original payload (provider agnostic).
1010
* @returns {Object} The payload according to Mailgun client specification.
1111
*/
12-
static mailgun(originalPayload) {
12+
static mailgun(data) {
1313

1414
// Clone payload
15-
const payload = Object.assign({}, originalPayload);
15+
const payload = Object.assign({}, data);
1616

1717
// Transform reply-to
1818
if (payload.replyTo) {
@@ -25,13 +25,13 @@ class ApiPayloadConverter {
2525

2626
/**
2727
* @description Converts the mail payload for the AWS Simple Mail Service (AWS JavaScript SDK v3).
28-
* @param {Object} originalPayload The original payload (provider agnostic).
28+
* @param {Object} data The original payload (provider agnostic).
2929
* @returns {Object} The payload according to AWS SDK specification.
3030
*/
31-
static awsSes(originalPayload) {
31+
static awsSes(data) {
3232

3333
// Clone payload
34-
const payload = Object.assign({}, originalPayload);
34+
const payload = Object.assign({}, data);
3535

3636
// Transform sender
3737
payload.Source = [payload.from];
@@ -92,6 +92,62 @@ class ApiPayloadConverter {
9292

9393
return payload;
9494
}
95+
96+
/**
97+
* Converts the mail payload for the ZeptoMail.
98+
* @param {Object} data The original payload
99+
* @param {String} data.api The provider API version.
100+
* @param {Object} data.payload The payload to convert to be compatible with the provider API.
101+
* @returns {Object} The payload according to ZeptoMail SDK specification.
102+
*/
103+
static zeptomail(data) {
104+
105+
// Clone payload
106+
const payload = Object.assign({}, data.payload);
107+
switch (data.api) {
108+
case '1.1': {
109+
110+
// Transform sender
111+
payload.from = {
112+
address: payload.from
113+
}
114+
const emailString = payload.to;
115+
const emailAddresses = emailString.split(',').map(email => email.trim());
116+
const formattedEmails = emailAddresses.map((address) => ({
117+
email_address: {
118+
address: address.trim()
119+
}
120+
}));
121+
payload.to = formattedEmails;
122+
if (payload.replyTo) {
123+
payload.reply_to = [{
124+
address: payload.replyTo
125+
}
126+
];
127+
delete payload.replyTo;
128+
}
129+
130+
// If message has content
131+
if (payload.subject || payload.textbody || payload.htmlbody) {
132+
if (payload.text || payload.html) {
133+
payload.textbody = {};
134+
if (payload.text) {
135+
payload.textbody = payload.text;
136+
delete payload.text;
137+
}
138+
if (payload.html) {
139+
payload.htmlbody = payload.html;
140+
delete payload.html;
141+
}
142+
}
143+
}
144+
break;
145+
}
146+
default:
147+
throw new Error(`Unsupported ZeptoMail API version '${ data.api }'.`);
148+
}
149+
return payload;
150+
}
95151
}
96152

97153
module.exports = ApiPayloadConverter;

0 commit comments

Comments
 (0)