Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions shortcuts/mail/mail_lint_writepath_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ func TestMailSend_WritePathLintAutofixesFontInEML(t *testing.T) {
"--to", "alice@example.com",
"--subject", "Send",
"--body", `<font color="red">payload</font>`,
"--no-signature",
"--show-lint-details",
}, f, stdout)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions shortcuts/mail/mail_request_receipt_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func TestMailSend_RequestReceiptAddsHeader_Integration(t *testing.T) {
"--to", "bob@example.com",
"--subject", "hi",
"--body", "please confirm",
"--no-signature",
"--request-receipt",
"--confirm-send",
}, f, stdout); err != nil {
Expand All @@ -153,6 +154,7 @@ func TestMailSend_RequestReceiptNoSender_FailsValidation(t *testing.T) {
"--to", "bob@example.com",
"--subject", "hi",
"--body", "body",
"--no-signature",
"--request-receipt",
"--confirm-send",
}, f, stdout)
Expand Down
30 changes: 25 additions & 5 deletions shortcuts/mail/mail_send.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ var MailSend = common.Shortcut{
{Name: "send-time", Desc: "Scheduled send time as a Unix timestamp in seconds. Must be at least 5 minutes in the future. Use with --confirm-send to schedule the email."},
{Name: "request-receipt", Type: "bool", Desc: "Request a read receipt (Message Disposition Notification, RFC 3798) addressed to the sender. Recipient mail clients may prompt the user, send automatically, or silently ignore — delivery of a receipt is not guaranteed."},
{Name: "template-id", Desc: "Optional. Apply a saved template by ID (decimal integer string) before composing. The template's subject/body/to/cc/bcc/attachments are merged with user-supplied flags (user flags win). Requires --as user."},
signatureFlag,
mailSendSignatureFlag,
mailSendNoSignatureFlag,
priorityFlag,
eventSummaryFlag, eventStartFlag, eventEndFlag, eventLocationFlag,
showLintDetailsFlag},
Expand All @@ -52,12 +53,27 @@ var MailSend = common.Shortcut{
if confirmSend {
desc = "Compose email → save as draft → send draft"
}
noSignature := runtime.Bool("no-signature")
api := common.NewDryRunAPI().Desc(desc)
if tid := runtime.Str("template-id"); tid != "" {
api = api.GET(templateMailboxPath(mailboxID, tid)).
Desc("Fetch template to merge with compose flags (subject/body/to/cc/bcc/attachments).")
}
api = api.GET(mailboxPath(mailboxID, "profile")).
Desc("Resolve mailbox profile and sender address.")
if !noSignature {
api = api.GET(mailboxPath(mailboxID, "settings", "signatures")).
Desc("Resolve explicit signature or default send signature.")
api = api.GET(mailboxPath(mailboxID, "settings", "send_as")).
Desc("Conditionally resolve sender identity for signature template variables.")
if aliasMailboxID := mailSendSignatureAliasMailboxID(mailboxID, runtime.Str("from")); aliasMailboxID != "" {
api = api.GET(mailboxPath(aliasMailboxID, "settings", "signatures")).
Desc("Fallback: resolve default send signature for the alias sender when the owning mailbox usage is absent.")
api = api.GET(mailboxPath(aliasMailboxID, "settings", "send_as")).
Desc("Fallback: resolve alias sender identity for signature template variables.")
}
}
api = api.
POST(mailboxPath(mailboxID, "drafts")).
Body(map[string]interface{}{
"raw": "<base64url-EML>",
Expand Down Expand Up @@ -98,7 +114,7 @@ var MailSend = common.Shortcut{
if err := validateSendTime(runtime); err != nil {
return err
}
if err := validateSignatureWithPlainText(runtime.Bool("plain-text"), runtime.Str("signature-id")); err != nil {
if err := validateMailSendSignatureFlags(runtime); err != nil {
return err
}
// Resolve the body content first (reading --body-file if set) so
Expand Down Expand Up @@ -135,6 +151,7 @@ var MailSend = common.Shortcut{
inlineFlag := runtime.Str("inline")
confirmSend := runtime.Bool("confirm-send")
sendTime := runtime.Str("send-time")
noSignature := runtime.Bool("no-signature")

senderEmail := resolveComposeSenderEmail(runtime)
signatureID := runtime.Str("signature-id")
Expand Down Expand Up @@ -195,7 +212,10 @@ var MailSend = common.Shortcut{
}
}

sigResult, err := resolveSignature(ctx, runtime, mailboxID, signatureID, senderEmail)
sigResult, err := resolveMailSendComposeSignature(ctx, runtime, mailboxID, senderEmail, mailSendSignatureOptions{
SignatureID: signatureID,
NoSignature: noSignature,
})
Comment thread
coderabbitai[bot] marked this conversation as resolved.
if err != nil {
return err
}
Expand Down Expand Up @@ -230,10 +250,10 @@ var MailSend = common.Shortcut{
// `lint_applied[]` / `original_blocked[]` even on the plain-text path.
lintApplied, lintBlocked := emptyLintEnvelopeFields()
if plainText {
composedTextBody = body
composedTextBody = appendMailSendPlainTextSignature(body, sigResult, resolveLang(runtime))
bld = bld.TextBody([]byte(composedTextBody))
} else if bodyIsHTML(body) || sigResult != nil {
// If signature is requested on plain-text body, auto-upgrade to HTML.
// Non-plain-text sends can use HTML so signatures keep their rich layout.
htmlBody := body
if !bodyIsHTML(body) {
htmlBody = buildBodyDiv(body, false)
Expand Down
3 changes: 3 additions & 0 deletions shortcuts/mail/mail_send_confirm_output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ func TestMailSendConfirmSendOutputsAutomationDisable(t *testing.T) {
"--to", "alice@example.com",
"--subject", "hello",
"--body", "world",
"--no-signature",
"--confirm-send",
}, f, stdout)
if err != nil {
Expand Down Expand Up @@ -203,6 +204,7 @@ func TestMailSendSaveDraftOutputsReference(t *testing.T) {
"--to", "alice@example.com",
"--subject", "hello",
"--body", "world",
"--no-signature",
}, f, stdout)
if err != nil {
t.Fatalf("save draft failed: %v", err)
Expand Down Expand Up @@ -243,6 +245,7 @@ func TestMailSend_WithCalendarEventEmbedded(t *testing.T) {
"--to", "alice@example.com",
"--subject", "Team Sync",
"--body", "<p>Please join us</p>",
"--no-signature",
"--event-summary", "Team Sync",
"--event-start", "2026-05-10T10:00+08:00",
"--event-end", "2026-05-10T11:00+08:00",
Expand Down
Loading
Loading