From 232b07cfebfb821446b727bc1bbbaaf7c9d32fd4 Mon Sep 17 00:00:00 2001 From: scottheng96 Date: Tue, 9 Jun 2026 11:50:48 +0800 Subject: [PATCH 1/3] feat: include replyTo and submissionId headers to MRF workflow completion email --- .../multirespondent-submission.service.ts | 4 ++++ .../multirespondent-submission.utils.ts | 16 ++++++++++++++++ .../src/app/services/mail/mail.service.ts | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts index 3ebe7551dd..9980fc2441 100644 --- a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts +++ b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts @@ -68,6 +68,7 @@ import { reportSubmissionResponseTime } from '../submissions.statsd-client' import { MultirespondentSubmissionContent } from './multirespondent-submission.types' import { + extractEmailAnswersFromResponses, extractRespondentCopyEmailDatas, formatSubmittedStepTimestamp, getEmailFromResponses, @@ -550,9 +551,12 @@ const sendMrfOutcomeEmails = ({ formId: form._id, formTitle: form.title, responseId: submissionId, + submissionId, timestamp: latestSubmissionTimestamp, formQuestionAnswers, attachments: emailAttachments, + replyTo: + extractEmailAnswersFromResponses(responses).join(', ') || undefined, }).orElse((error) => { logger.error({ message: 'Failed to send workflow completion email', diff --git a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts index 670ce3b9be..8b1d426d55 100644 --- a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts +++ b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts @@ -109,6 +109,22 @@ export const getEmailFromResponses = ( return field.answer.value } +export const extractEmailAnswersFromResponses = ( + responses: FieldResponsesV3, +): string[] => { + return Object.values(responses) + .filter( + ( + response, + ): response is Extract< + FieldResponseV3, + { fieldType: BasicField.Email } + > => response.fieldType === BasicField.Email, + ) + .map((response) => response.answer.value) + .filter(Boolean) +} + const getConditionalFieldEmailRecipient = ( form_fields: FormFieldSchema[] | FormFieldDto[], fieldId: string, diff --git a/apps/backend/src/app/services/mail/mail.service.ts b/apps/backend/src/app/services/mail/mail.service.ts index 5d9ba2dcb3..8ee1b02d4c 100644 --- a/apps/backend/src/app/services/mail/mail.service.ts +++ b/apps/backend/src/app/services/mail/mail.service.ts @@ -1186,17 +1186,21 @@ export class MailService { formId, formTitle, responseId, + submissionId, timestamp, formQuestionAnswers, attachments, + replyTo, }: { emails: string[] formId: string formTitle: string responseId: string + submissionId?: string timestamp: string formQuestionAnswers: QuestionAnswer[] attachments?: Mail.Attachment[] + replyTo?: string }): ResultAsync => { const emailTemplateData: EmailData = { formTitle, @@ -1213,6 +1217,8 @@ export class MailService { attachments, emailType: EmailType.WorkflowCompletion, actionName: 'sendMrfWorkflowCompletionEmail', + submissionId, + replyTo, }) } From fd2b58b1279d7e840005c365a8e329f44f3e4974 Mon Sep 17 00:00:00 2001 From: scottheng96 Date: Tue, 9 Jun 2026 11:52:02 +0800 Subject: [PATCH 2/3] feat: add reply-To and submissionid to headers for approval emails --- .../multirespondent-submission.service.ts | 4 ++++ apps/backend/src/app/services/mail/mail.service.ts | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts index 9980fc2441..d188081bcb 100644 --- a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts +++ b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts @@ -528,10 +528,14 @@ const sendMrfOutcomeEmails = ({ formId: form._id, formTitle: form.title, responseId: submissionId, + submissionId, timestamp: latestSubmissionTimestamp, isRejected, formQuestionAnswers, attachments: emailAttachments, + replyTo: + extractEmailAnswersFromResponses(responses).join(', ') || + undefined, }).orElse((error) => { logger.error({ message: 'Failed to send approval email', diff --git a/apps/backend/src/app/services/mail/mail.service.ts b/apps/backend/src/app/services/mail/mail.service.ts index 8ee1b02d4c..fffbb263d8 100644 --- a/apps/backend/src/app/services/mail/mail.service.ts +++ b/apps/backend/src/app/services/mail/mail.service.ts @@ -1227,19 +1227,23 @@ export class MailService { formId, formTitle, responseId, + submissionId, timestamp, isRejected, formQuestionAnswers, attachments, + replyTo, }: { emails: string[] formId: string formTitle: string responseId: string + submissionId?: string timestamp: string isRejected: boolean formQuestionAnswers: QuestionAnswer[] attachments?: Mail.Attachment[] + replyTo?: string }): ResultAsync => { const outcome = isRejected ? WorkflowOutcome.NOT_APPROVED @@ -1261,6 +1265,8 @@ export class MailService { attachments, emailType: EmailType.WorkflowApproval, actionName: 'sendMrfApprovalEmail', + submissionId, + replyTo, }) } From e56ede29f9d652676f04ae01be3afaade0764af8 Mon Sep 17 00:00:00 2001 From: scottheng96 Date: Tue, 9 Jun 2026 12:13:32 +0800 Subject: [PATCH 3/3] fix: formId header, fix empty responses early return for extract email function --- .../multirespondent-submission.service.ts | 4 ++-- .../multirespondent-submission.utils.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts index d188081bcb..a79ed4e9b7 100644 --- a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts +++ b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.service.ts @@ -525,7 +525,7 @@ const sendMrfOutcomeEmails = ({ if (isApproval) { return MailService.sendMrfApprovalEmail({ emails: destinationEmails, - formId: form._id, + formId: String(form._id), formTitle: form.title, responseId: submissionId, submissionId, @@ -552,7 +552,7 @@ const sendMrfOutcomeEmails = ({ return MailService.sendMrfWorkflowCompletionEmail({ emails: destinationEmails, - formId: form._id, + formId: String(form._id), formTitle: form.title, responseId: submissionId, submissionId, diff --git a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts index 8b1d426d55..191fbb95d3 100644 --- a/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts +++ b/apps/backend/src/app/modules/submission/multirespondent-submission/multirespondent-submission.utils.ts @@ -112,6 +112,7 @@ export const getEmailFromResponses = ( export const extractEmailAnswersFromResponses = ( responses: FieldResponsesV3, ): string[] => { + if (!responses) return [] return Object.values(responses) .filter( (