Skip to content

Commit

Permalink
Send mails to all members in chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
UrsMetz committed Nov 10, 2024
1 parent e582dd5 commit 9b41218
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 6 deletions.
2 changes: 1 addition & 1 deletion softwerkskammer/lib/mailsender/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async function messageSubmitted(req, res) {

async function doTheRightSending() {
if (req.body.massMailing === "members") {
return mailsenderService.sendMailToAllMembers(message);
return mailsenderService.sendMailToAllMembers(message, sender);
}
const activityURL = req.body.successURL.replace("/activities/", "");
if (req.body.toParticipants) {
Expand Down
9 changes: 4 additions & 5 deletions softwerkskammer/lib/mailsender/mailsenderService.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ function createChunkedSendingReportMessage(statusmessages, subject, sender) {
}

function sendMailInChunks(maxMailSendingChunkSize, allMembers, message, type, sender) {
const splitted = R.splitEvery(maxMailSendingChunkSize, allMembers);
const membersInChunks = R.splitEvery(maxMailSendingChunkSize, allMembers);

Promise.all(
splitted.map((bccs) => {
membersInChunks.map((bccs) => {
message.setBccToMemberAddresses(bccs);
return sendMail(message, type);
}),
Expand Down Expand Up @@ -185,11 +185,10 @@ module.exports = {
}
},

sendMailToAllMembers: async function sendMailToAllMembers(message) {
sendMailToAllMembers: async function sendMailToAllMembers(message, sender) {
const type = "$t(mailsender.notification)";
const members = memberstore.allMembers();
message.setBccToMemberAddresses(members);
return sendMail(message, type);
return sendMailInChunks(conf.get("maxMailSendingChunkSize"), members, message, type, sender);
},

sendMagicLinkToMember: async function sendMagicLinkToMember(member, token) {
Expand Down
124 changes: 124 additions & 0 deletions softwerkskammer/test/mailsender/mailsenderService_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -667,4 +667,128 @@ describe("MailsenderService", () => {
});
});
});

describe("sending to all members", () => {
const member1 = new Member({ email: "memberA" });
const member2 = new Member({ email: "memberB" });

beforeEach(() => {
sinon.stub(memberstore, "allMembers").callsFake(() => {
return [member1, member2];
});
})

Check failure on line 679 in softwerkskammer/test/mailsender/mailsenderService_test.js

View workflow job for this annotation

GitHub Actions / build

Insert `;`

Check failure on line 679 in softwerkskammer/test/mailsender/mailsenderService_test.js

View workflow job for this annotation

GitHub Actions / build

Missing semicolon

it("sends in chunks to all members", async () => {
const statusmessage = await mailsenderService.sendMailToAllMembers(message, sender);
const allSent = allSentEmail();
const sentMail1 = allSent[0];
expect(sentMail1.bcc).to.eql(["memberA", "memberB"]);

expect(statusmessage.contents().type).to.equal("alert-success");
});

it("sends status mail to intiator after all mails have been sent", async () => {
let mailsSentCount = 0;
let myResolve;
const allExpectedMailsSent = new Promise((resolve) => {
myResolve = resolve;
});
sendmail.reset();
sendmail.callsFake(() => {
mailsSentCount++;

if (mailsSentCount >= 2) {
myResolve(undefined);
}
});

let statusmessage = await mailsenderService.sendMailToAllMembers(message, sender);

expect(statusmessage.contents().type).to.equal("alert-success");
expect(statusmessage.contents().text).to.equal("message.content.mailsender.success");

await allExpectedMailsSent;
const allSent = allSentEmail();

expect(allSent).to.have.length(2);

expect(allSent[1].to).to.equal(sender.email());
expect(allSent[1].subject).to.contain("Report");
expect(allSent[1].subject).to.contain(mailSubject);
expect(allSent[1].html).to.contain("erfolgreich");
});

it("returns success regardless of mail sending result", async () => {
sendmail.callsFake(() => {
throw new Error();
});

const statusmessage = await mailsenderService.sendMailToAllMembers(message, sender);

expect(statusmessage.contents().type).to.equal("alert-success");
});

it("includes errors in send report mail from Error", async () => {
let mailsSentCount = 0;
let myResolve;
const allExpectedMailsSent = new Promise((resolve) => {
myResolve = resolve;
});
sendmail.reset();
sendmail.callsFake(() => {
mailsSentCount++;

if (mailsSentCount >= 2) {
myResolve(undefined);
} else {
throw new Error("Error: das hat nicht geklappt");
}
});

await mailsenderService.sendMailToAllMembers(message, sender);

await allExpectedMailsSent;

const sentEmails = allSentEmail();
expect(sentEmails).to.have.length(2);
expect(sentEmails[1].to).to.contain(sender.email());
expect(sentEmails[1].subject).to.contain("Report");
expect(sentEmails[1].subject).to.contain(mailSubject);
expect(sentEmails[1].html).to.contain("Fehler");
expect(sentEmails[1].html).to.contain("Error: das hat nicht geklappt");
});

it("includes errors in send report mail from Promise rejection", async () => {
let mailsSentCount = 0;
let myResolve;
const allExpectedMailsSent = new Promise((resolve) => {
myResolve = resolve;
});
sendmail.reset();
sendmail.callsFake(() => {
mailsSentCount++;

if (mailsSentCount >= 2) {
myResolve(undefined);
} else {
return Promise.reject("Promise: das hat nicht geklappt");
}
});
sinon.stub(groupsAndMembersService, "addMembersToGroup").callsFake((group) => {
group.members = membersAboveSingleChunkThreshhold;
});

await mailsenderService.sendMailToAllMembers(message, sender);

await allExpectedMailsSent;

const sentEmails = allSentEmail();
expect(sentEmails).to.have.length(2);
expect(sentEmails[1].to).to.contain(sender.email());
expect(sentEmails[1].subject).to.contain("Report");
expect(sentEmails[1].subject).to.contain(mailSubject);
expect(sentEmails[1].html).to.contain("Fehler");
expect(sentEmails[1].html).to.contain("Promise: das hat nicht geklappt");
});
});
});

0 comments on commit 9b41218

Please sign in to comment.