graph: use replyTo instead of from to avoid ErrorSendAsDenied
This commit is contained in:
Vendored
+25
-18
@@ -89,10 +89,18 @@ import { getSiteIntegrations } from '../payload/index.js';
|
||||
sent: false
|
||||
};
|
||||
}
|
||||
// From-display comes from the panel; falls back to the caller's from.
|
||||
// The panel's from-address is used as Reply-To, NOT as the message From.
|
||||
//
|
||||
// Why: app-only Graph sends from GRAPH_SENDER's mailbox. If we also set a
|
||||
// `from` that differs from that mailbox, Exchange demands "Send As"
|
||||
// permission on it and rejects with ErrorSendAsDenied otherwise. So we
|
||||
// never override `from` — Graph stamps the mail as GRAPH_SENDER (the
|
||||
// mailbox we legitimately own) — and route replies to the panel address
|
||||
// via Reply-To. Recipients see the mail from forms@… but replying reaches
|
||||
// the real destination. No Send-As needed.
|
||||
const panel = await getSiteIntegrations(payload);
|
||||
const fromAddress = panel.smtpFromAddress || undefined;
|
||||
const fromName = panel.smtpFromName || undefined;
|
||||
const replyToAddress = panel.smtpFromAddress || undefined;
|
||||
const replyToName = panel.smtpFromName || undefined;
|
||||
const to = toRecipients(message.to);
|
||||
if (to.length === 0) {
|
||||
payload.logger.error('[ipal] Email not sent: no valid recipient.');
|
||||
@@ -104,6 +112,17 @@ import { getSiteIntegrations } from '../payload/index.js';
|
||||
// Graph accepts either HTML or Text; Payload gives us html and/or text.
|
||||
const isHtml = typeof message.html === 'string' && message.html.length > 0;
|
||||
const content = isHtml ? String(message.html) : String(message.text ?? '');
|
||||
// Reply-To: prefer whatever the caller set; otherwise the panel address.
|
||||
const replyTo = message.replyTo ? toRecipients(message.replyTo) : replyToAddress ? [
|
||||
{
|
||||
emailAddress: {
|
||||
address: replyToAddress,
|
||||
...replyToName ? {
|
||||
name: replyToName
|
||||
} : {}
|
||||
}
|
||||
}
|
||||
] : [];
|
||||
const graphMessage = {
|
||||
body: {
|
||||
content,
|
||||
@@ -117,21 +136,9 @@ import { getSiteIntegrations } from '../payload/index.js';
|
||||
...message.bcc ? {
|
||||
bccRecipients: toRecipients(message.bcc)
|
||||
} : {},
|
||||
// from is only honoured if the app has Send-As for that address; when
|
||||
// it's the shared mailbox itself, omit it and Graph uses the sender.
|
||||
...fromAddress ? {
|
||||
from: {
|
||||
emailAddress: {
|
||||
address: fromAddress,
|
||||
...fromName ? {
|
||||
name: fromName
|
||||
} : {}
|
||||
}
|
||||
}
|
||||
} : {},
|
||||
// replyTo lets the recipient reply to the real submitter if the caller set it.
|
||||
...message.replyTo ? {
|
||||
replyTo: toRecipients(message.replyTo)
|
||||
// NO `from` — Graph uses GRAPH_SENDER's own mailbox, so no Send-As.
|
||||
...replyTo.length > 0 ? {
|
||||
replyTo
|
||||
} : {}
|
||||
};
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user