Skip to content
This repository was archived by the owner on Apr 22, 2024. It is now read-only.

Commit 3e3ece4

Browse files
authored
Add microsoftl365 email sender
* Add microsoftl365 email sender * Test and lint mail365 Co-authored-by: Carlo Minotti <[email protected]>
1 parent aec1bf6 commit 3e3ece4

File tree

3 files changed

+177
-1
lines changed

3 files changed

+177
-1
lines changed

server/boot/graph-mail.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"use strict";
2+
const config = require("../../server/config.local");
3+
const superagent = require("superagent");
4+
5+
class M365Authenticate {
6+
constructor(config){
7+
this.tenantId = config.auth.tenantId || "";
8+
this.clientId = config.auth.clientId || "";
9+
this.clientSecret = config.auth.clientSecret || "";
10+
this.aadEndpoint = config.aadEndpoint || "";
11+
this.graphEndpoint = config.graphEndpoint || "";
12+
}
13+
14+
async getAuthToken() {
15+
const formData = {
16+
"grant_type": "client_credentials",
17+
scope: `${this.graphEndpoint}/.default`,
18+
"client_id": this.clientId,
19+
"client_secret": this.clientSecret,
20+
};
21+
22+
const tokenObject = await superagent.post(
23+
`${this.aadEndpoint}/${this.tenantId}/oauth2/v2.0/token`)
24+
.set({ "Content-Type": "application/x-www-form-urlencoded" })
25+
.send(formData);
26+
return tokenObject.body.access_token;
27+
}
28+
29+
}
30+
31+
class M365Email {
32+
constructor(authClass) {
33+
this.authClass = authClass;
34+
this.graphEndpoint = authClass.graphEndpoint;
35+
}
36+
37+
createRecipients(rcpts) {
38+
return rcpts.filter(r => r).map((rcpt) => {
39+
return {
40+
emailAddress: {
41+
address: rcpt,
42+
},
43+
};
44+
});
45+
}
46+
47+
createEmailAsJson(rcpts, body, from, replyTo, subject) {
48+
let messageAsJson = {
49+
message: {
50+
subject: subject,
51+
from: {
52+
emailAddress: { address: from }
53+
},
54+
replyTo: [{
55+
emailAddress: { address: replyTo }
56+
}],
57+
body: {
58+
contentType: "HTML",
59+
content: body,
60+
},
61+
},
62+
};
63+
64+
messageAsJson = this.addRecipients(messageAsJson, rcpts);
65+
return messageAsJson;
66+
}
67+
68+
async sendNotification(from, message){
69+
const accessToken = await this.authClass.getAuthToken();
70+
try {
71+
const response = await superagent.post(
72+
`${this.graphEndpoint}/v1.0/users/${from}/sendMail`)
73+
.set({ Authorization: `Bearer ${accessToken}` })
74+
.set({ "Content-Type": "application/json" })
75+
.send(message);
76+
77+
console.log("sendNotification status", response.statusText);
78+
} catch (error) {
79+
console.log(error);
80+
}
81+
}
82+
83+
addRecipients(messageBody, rcpts = {}) {
84+
const cloned = Object.assign({}, messageBody);
85+
86+
Object.keys(rcpts).forEach((element) => {
87+
const recipients = this.createRecipients(rcpts[element]);
88+
if (recipients.length > 0) {
89+
cloned.message[element + "Recipients"] = recipients;
90+
}
91+
});
92+
93+
return cloned;
94+
}
95+
96+
}
97+
98+
exports.M365Email = M365Email;
99+
100+
exports.sendEmailM365 = async(to, cc, subjectText, mailText, e, next, html = null) => {
101+
try {
102+
const client = new M365Authenticate(config.smtpSettings);
103+
const emailSender = new M365Email(client);
104+
const messageCofig = config.smtpMessage;
105+
const message = emailSender.createEmailAsJson(
106+
{ to: to.split(","), cc: cc ?cc.split(","): [] },
107+
html,
108+
messageCofig.from,
109+
messageCofig.replyTo,
110+
messageCofig.subject
111+
);
112+
emailSender.sendNotification(messageCofig.from, message);
113+
} catch (err) {
114+
console.log(err);
115+
}
116+
return next && next(e);
117+
};

server/boot/handleJobSideEffects.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ const fs = require("fs");
33
const config = require("../config.local");
44
const utils = require("../../common/models/utils");
55
const Handlerbars = require("handlebars");
6+
const graphMail = require("./graph-mail");
67
module.exports = (app) => {
78

9+
const sendMail = config.smtpSettings && config.smtpSettings.graphEndpoint ? graphMail.sendEmailM365: utils.sendMail;
810
const Job = app.models.Job;
911
const jobTypes = Job.types;
1012
const Dataset = app.models.Dataset;
@@ -72,7 +74,7 @@ module.exports = (app) => {
7274
const emailTemplate = Handlerbars.compile(htmlTemplate);
7375
const email = emailTemplate(emailContext);
7476
const subject = emailContext.subject;
75-
utils.sendMail(to, cc, subject, null, null, null, email);
77+
sendMail(to, cc, subject, null, null, null, email);
7678
};
7779

7880
// Check policy settings if mail should be sent

test/graph-mail.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"use strict";
2+
3+
const { sendEmailM365, M365Email } = require("../server/boot/graph-mail.js");
4+
const sandbox = require("sinon").createSandbox();
5+
const { expect } = require("chai");
6+
const config = require("../server/config.local");
7+
8+
afterEach((done) => {
9+
sandbox.restore();
10+
done();
11+
});
12+
13+
describe("server.boot.graph-mail", () => {
14+
15+
it("should sendEmailM365", () => {
16+
const sendNotificationStub = sandbox.stub(M365Email.prototype, "sendNotification");
17+
if (!config.smtpSettings) config.smtpSettings = {};
18+
sandbox.stub(config, "smtpSettings").value({
19+
auth: {
20+
tenantId: "someTenant",
21+
clientId: "someClientId",
22+
clientSecret: "someClientSecret"
23+
}
24+
});
25+
const from = "[email protected]";
26+
if (!config.smtpMessage) config.smtpMessage = {};
27+
sandbox.stub(config, "smtpMessage").value({
28+
29+
replyTo: "[email protected]",
30+
subject: "this is a subject",
31+
});
32+
const body = "<h1>Test from James A</h1><p>HTML message sent via MS Graph</p>";
33+
sendEmailM365("[email protected],[email protected]", "", null, null, null, null, body);
34+
const expectedMessage = {
35+
message:{
36+
subject:"this is a subject",
37+
from:{
38+
emailAddress:{
39+
address:"[email protected]"
40+
}
41+
},
42+
replyTo:[
43+
{ emailAddress:{ address:"[email protected]" } }
44+
],
45+
body:{
46+
contentType:"HTML",
47+
content:"<h1>Test from James A</h1><p>HTML message sent via MS Graph</p>" },
48+
toRecipients:[
49+
{ emailAddress:{ address:"[email protected]" } },
50+
{ emailAddress:{ address:"[email protected]" } }
51+
]
52+
}
53+
};
54+
expect(sendNotificationStub.calledWith(from, expectedMessage)).to.be.true;
55+
});
56+
57+
});

0 commit comments

Comments
 (0)