feat(email): accept custom message headers in sendRaw (#3411)
Maintain Release Merge PR / update-release-pr (push) Canceled after 0s
Notify HeyPuter / notify (push) Canceled after 0s
release-please / release-please (push) Canceled after 0s

* feat(email): accept custom message headers in sendRaw

Lets callers set transport-level headers such as List-Unsubscribe /
List-Unsubscribe-Post. Also documents the puter-email driver's automatic
unsubscribe / report-abuse footer and the new `suppressed` result field
in the puter.js email module.

* feat(email): envelope override in sendRaw + suppressed in EmailSendResult type

Adds an optional `envelope` field to SendMailOptions so callers can set
transport recipients independently of the visible To/Cc headers (used by
the email-send driver for per-recipient deliveries), and adds the
`suppressed: string[]` field to the public EmailSendResult typing to
match the driver's documented result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(email): document per-recipient best-effort delivery via `failed`

The email-send driver now attempts every recipient's private delivery
even when one fails, returning failed addresses in the result's
`failed` array instead of failing the whole call — so callers retry
only the failed subset and never re-mail delivered recipients. Adds
the field to the public EmailSendResult typing and module docs.
This commit is contained in:
Nariman Jelveh
2026-07-20 11:55:46 -07:00
committed by GitHub
parent dd314da16d
commit f5d656650f
3 changed files with 26 additions and 1 deletions
+7
View File
@@ -45,11 +45,18 @@ export interface SendMailOptions {
to: string;
cc?: string;
bcc?: string;
/** Optional transport recipients when they differ from visible headers. */
envelope?: {
from?: string;
to: string;
};
subject: string;
html?: string;
text?: string;
replyTo?: string;
attachments?: EmailAttachment[];
/** Extra message headers (e.g. List-Unsubscribe), passed to the transport. */
headers?: Record<string, string>;
}
export type EmailValidator = (email: string) => Promise<boolean> | boolean;
+10
View File
@@ -22,6 +22,16 @@ import * as utils from '../lib/utils.js';
* });
*
* Positional form: `await puter.email.send(to, subject, body)`.
*
* Every mail automatically gets an unsubscribe / report-abuse footer.
* Recipients who unsubscribe are dropped from future sends — they come
* back in the result's `suppressed` array — and a send whose `to` list
* is entirely unsubscribed is rejected.
*
* Each recipient gets a private delivery. A recipient whose delivery
* fails comes back in the result's `failed` array (everyone else got
* their copy — retry with just those addresses); the call only rejects
* when no recipient could be delivered.
*/
class Email {
/**
+9 -1
View File
@@ -36,10 +36,18 @@ export interface EmailSendOptions {
}
export interface EmailSendResult {
/** Transport message id, when the mail server reports one. */
/** First transport message id reported for this send, when available. */
messageId: string | null;
/** Total charge for this send, in microcents. */
cost: number;
/** Recipients omitted because they opted out of this sender's mail. */
suppressed: string[];
/**
* Recipients whose delivery attempt failed. Everyone else got their
* copy — retry with just these addresses. A send where every delivery
* fails rejects instead.
*/
failed: string[];
}
/**