Skip to content

Commit 8114775

Browse files
authored
Merge pull request #58 from aolamide/feat/add-reply-to
Feature to add "reply_to" option when sending mails.
2 parents 52afee1 + 089b7f5 commit 8114775

File tree

7 files changed

+101
-2
lines changed

7 files changed

+101
-2
lines changed

examples/sending/everything.ts

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { MailtrapClient } from "mailtrap"
1212
const TOKEN = "<YOUR-TOKEN-HERE>";
1313
const SENDER_EMAIL = "<[email protected]>";
1414
const RECIPIENT_EMAIL = "<[email protected]>";
15+
const REPLY_TO_EMAIL = "<[email protected]>";
1516

1617
const client = new MailtrapClient({ token: TOKEN });
1718

@@ -28,6 +29,7 @@ client
2829
from: { name: "Mailtrap Test", email: SENDER_EMAIL },
2930
to: [{ email: RECIPIENT_EMAIL }],
3031
subject: "Hello from Mailtrap!",
32+
reply_to: { email: REPLY_TO_EMAIL },
3133
html: `
3234
<!doctype html>
3335
<html>

examples/sending/transport.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { MailtrapTransport } from "mailtrap"
1111
const TOKEN = "<YOUR-TOKEN-HERE>"
1212
const SENDER_EMAIL = "<[email protected]>";
1313
const RECIPIENT_EMAIL = "<[email protected]>";
14+
const REPLY_TO_EMAIL = "<[email protected]>";
1415

1516
const transport = Nodemailer.createTransport(MailtrapTransport({
1617
token: TOKEN,
@@ -26,6 +27,7 @@ transport.sendMail({
2627
address: SENDER_EMAIL,
2728
name: "Mailtrap Test"
2829
},
30+
replyTo: REPLY_TO_EMAIL,
2931
subject: "Hello from Mailtrap!",
3032
html: `
3133
<!doctype html>

src/__tests__/adapters/mail.test.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import adaptMail from "../../adapters/mail";
22

33
import config from "../../config";
4-
import { adaptSingleRecipient } from "../../adapters/recipients";
4+
import {
5+
adaptSingleRecipient,
6+
adaptReplyToRecipient,
7+
} from "../../adapters/recipients";
58

69
const { ERRORS } = config;
710
const { SUBJECT_REQUIRED, FROM_REQUIRED } = ERRORS;
@@ -24,6 +27,7 @@ describe("adapters/mail: ", () => {
2427
mockKey: "mock-value",
2528
},
2629
subject: "mock-subject",
30+
replyTo: "mock-reply-to",
2731
};
2832

2933
const expectedResult = {
@@ -33,6 +37,7 @@ describe("adapters/mail: ", () => {
3337
bcc: [],
3438
headers: data.headers,
3539
subject: data.subject,
40+
reply_to: adaptReplyToRecipient(data.replyTo),
3641
};
3742
const result = adaptMail(data);
3843

@@ -47,6 +52,7 @@ describe("adapters/mail: ", () => {
4752
mockKey: "mock-value",
4853
},
4954
attachments: [{ filename: "mock-filename", content: "mock-content" }],
55+
replyTo: [],
5056
};
5157

5258
const expectedResult = {
@@ -57,6 +63,7 @@ describe("adapters/mail: ", () => {
5763
bcc: [],
5864
headers: data.headers,
5965
attachments: data.attachments,
66+
reply_to: adaptReplyToRecipient(data.replyTo),
6067
};
6168
const result = adaptMail(data);
6269

@@ -74,6 +81,7 @@ describe("adapters/mail: ", () => {
7481
customVariables: {
7582
user_id: "mock-user_id",
7683
},
84+
replyTo: ["mock-reply-to"],
7785
};
7886

7987
const expectedResult = {
@@ -85,6 +93,7 @@ describe("adapters/mail: ", () => {
8593
headers: data.headers,
8694
attachments: data.attachments,
8795
custom_variables: data.customVariables,
96+
reply_to: adaptReplyToRecipient(data.replyTo),
8897
};
8998
const result = adaptMail(data);
9099

src/__tests__/adapters/recipients.test.ts

+57
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import adaptRecipients, {
22
adaptSingleRecipient,
3+
adaptReplyToRecipient,
34
} from "../../adapters/recipients";
45

56
describe("adapters/recipients: ", () => {
@@ -85,4 +86,60 @@ describe("adapters/recipients: ", () => {
8586
expect(result).toEqual(expectedResult);
8687
});
8788
});
89+
90+
describe("adaptReplyToRecipient(): ", () => {
91+
it("returns undefined if recipients is invalid.", () => {
92+
const recipients = undefined;
93+
94+
const expectedResult = undefined;
95+
const result = adaptReplyToRecipient(recipients);
96+
97+
expect(result).toEqual(expectedResult);
98+
});
99+
100+
it("returns undefined if recipients is empty array.", () => {
101+
const recipients: any = [];
102+
103+
const expectedResult = undefined;
104+
const result = adaptReplyToRecipient(recipients);
105+
106+
expect(result).toEqual(expectedResult);
107+
});
108+
109+
it("returns adapted recipients if it's not an array.", () => {
110+
const recipients = {
111+
name: "mock-name",
112+
address: "mock-email",
113+
};
114+
115+
const expectedResult = {
116+
name: recipients.name,
117+
email: recipients.address,
118+
};
119+
const result = adaptReplyToRecipient(recipients);
120+
121+
expect(result).toEqual(expectedResult);
122+
});
123+
124+
it("returns first adapted recipient if it's an array.", () => {
125+
const recipients = [
126+
{
127+
name: "mock-name-1",
128+
address: "mock-email-1",
129+
},
130+
{
131+
name: "mock-name-2",
132+
address: "mock-email-2",
133+
},
134+
];
135+
136+
const expectedResult = {
137+
name: recipients[0].name,
138+
email: recipients[0].address,
139+
};
140+
const result = adaptReplyToRecipient(recipients);
141+
142+
expect(result).toEqual(expectedResult);
143+
});
144+
});
88145
});

src/adapters/mail.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import adaptAttachment from "./attachement";
22
import adaptContent from "./content";
33
import adaptHeaders from "./headers";
4-
import adaptRecipients, { adaptSingleRecipient } from "./recipients";
4+
import adaptRecipients, {
5+
adaptSingleRecipient,
6+
adaptReplyToRecipient,
7+
} from "./recipients";
58

69
import CONFIG from "../config";
710

@@ -27,6 +30,7 @@ export default function adaptMail(data: MailtrapMailOptions): Mail | SendError {
2730
to: adaptRecipients(data.to),
2831
cc: adaptRecipients(data.cc),
2932
bcc: adaptRecipients(data.bcc),
33+
reply_to: adaptReplyToRecipient(data.replyTo),
3034
};
3135

3236
if (data.headers) {

src/adapters/recipients.ts

+24
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,27 @@ export default function adaptRecipients(
3838

3939
return recipients.map(adaptSingleRecipient);
4040
}
41+
42+
/**
43+
* If there is no recipient or empty array is passed, then return undefined since it is an optional field.
44+
* If it's not array, then adapt recipient and returns it.
45+
* Otherwise, if type is array as nodemailer allows, we pick the first recipient
46+
* as Mailtrap doesn't support multiple reply-to recipients.
47+
*/
48+
export function adaptReplyToRecipient(
49+
recipients:
50+
| string
51+
| NodemailerAddress
52+
| Array<string | NodemailerAddress>
53+
| undefined
54+
): Address | undefined {
55+
if (!recipients || (Array.isArray(recipients) && recipients.length === 0)) {
56+
return undefined;
57+
}
58+
59+
if (!Array.isArray(recipients)) {
60+
return adaptSingleRecipient(recipients);
61+
}
62+
63+
return adaptSingleRecipient(recipients[0]);
64+
}

src/types/mailtrap.ts

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type CommonMail = {
2323
attachments?: Attachment[];
2424
headers?: MailtrapHeaders;
2525
custom_variables?: CustomVariables;
26+
reply_to?: Address;
2627
};
2728

2829
export type TemplateVariables = Record<string, string | number | boolean>;

0 commit comments

Comments
 (0)