Skip to content

Commit 35c0cf1

Browse files
feat(gmail): add --quote support to draft replies
1 parent e4bf53b commit 35c0cf1

3 files changed

Lines changed: 469 additions & 3 deletions

File tree

internal/cmd/gmail_drafts.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ type GmailDraftsCreateCmd struct {
293293
BodyHTML string `name:"body-html" help:"Body (HTML; optional)"`
294294
ReplyToMessageID string `name:"reply-to-message-id" help:"Reply to Gmail message ID (sets In-Reply-To/References and thread)"`
295295
ReplyTo string `name:"reply-to" help:"Reply-To header address"`
296+
Quote bool `name:"quote" help:"Include quoted original message in reply (requires --reply-to-message-id)"`
296297
Attach []string `name:"attach" help:"Attachment file path (repeatable)"`
297298
From string `name:"from" help:"Send from this email address (must be a verified send-as alias)"`
298299
}
@@ -307,6 +308,7 @@ type draftComposeInput struct {
307308
ReplyToMessageID string
308309
ReplyToThreadID string
309310
ReplyTo string
311+
Quote bool
310312
Attach []string
311313
From string
312314
}
@@ -337,13 +339,14 @@ func buildDraftMessage(ctx context.Context, svc *gmail.Service, account string,
337339
}
338340
}
339341

340-
info, err := fetchReplyInfo(ctx, svc, input.ReplyToMessageID, input.ReplyToThreadID, false)
342+
info, err := fetchReplyInfo(ctx, svc, input.ReplyToMessageID, input.ReplyToThreadID, input.Quote)
341343
if err != nil {
342344
return nil, "", err
343345
}
344346
inReplyTo := info.InReplyTo
345347
references := info.References
346348
threadID := info.ThreadID
349+
body, htmlBody := applyQuoteToBodies(input.Body, input.BodyHTML, input.Quote, info)
347350

348351
atts := make([]mailAttachment, 0, len(input.Attach))
349352
for _, p := range input.Attach {
@@ -361,8 +364,8 @@ func buildDraftMessage(ctx context.Context, svc *gmail.Service, account string,
361364
Bcc: splitCSV(input.Bcc),
362365
ReplyTo: input.ReplyTo,
363366
Subject: input.Subject,
364-
Body: input.Body,
365-
BodyHTML: input.BodyHTML,
367+
Body: body,
368+
BodyHTML: htmlBody,
366369
InReplyTo: inReplyTo,
367370
References: references,
368371
Attachments: atts,
@@ -410,6 +413,9 @@ func (c *GmailDraftsCreateCmd) Run(ctx context.Context, flags *RootFlags) error
410413
return err
411414
}
412415
replyToMessageID := normalizeGmailMessageID(c.ReplyToMessageID)
416+
if c.Quote && replyToMessageID == "" {
417+
return usage("--quote requires --reply-to-message-id")
418+
}
413419

414420
attachPaths := make([]string, 0, len(c.Attach))
415421
for _, p := range c.Attach {
@@ -430,6 +436,7 @@ func (c *GmailDraftsCreateCmd) Run(ctx context.Context, flags *RootFlags) error
430436
ReplyToMessageID: replyToMessageID,
431437
ReplyToThreadID: "",
432438
ReplyTo: c.ReplyTo,
439+
Quote: c.Quote,
433440
Attach: attachPaths,
434441
From: c.From,
435442
}
@@ -446,6 +453,7 @@ func (c *GmailDraftsCreateCmd) Run(ctx context.Context, flags *RootFlags) error
446453
"body_html_len": len(strings.TrimSpace(input.BodyHTML)),
447454
"reply_to_message_id": strings.TrimSpace(input.ReplyToMessageID),
448455
"reply_to": strings.TrimSpace(input.ReplyTo),
456+
"quote": input.Quote,
449457
"from": strings.TrimSpace(input.From),
450458
"attachments": attachPaths,
451459
}); dryRunErr != nil {
@@ -485,6 +493,7 @@ type GmailDraftsUpdateCmd struct {
485493
BodyHTML string `name:"body-html" help:"Body (HTML; optional)"`
486494
ReplyToMessageID string `name:"reply-to-message-id" help:"Reply to Gmail message ID (sets In-Reply-To/References and thread)"`
487495
ReplyTo string `name:"reply-to" help:"Reply-To header address"`
496+
Quote bool `name:"quote" help:"Include quoted original message in reply"`
488497
Attach []string `name:"attach" help:"Attachment file path (repeatable)"`
489498
From string `name:"from" help:"Send from this email address (must be a verified send-as alias)"`
490499
}
@@ -528,6 +537,7 @@ func (c *GmailDraftsUpdateCmd) Run(ctx context.Context, flags *RootFlags) error
528537
ReplyToMessageID: replyToMessageID,
529538
ReplyToThreadID: "",
530539
ReplyTo: c.ReplyTo,
540+
Quote: c.Quote,
531541
Attach: attachPaths,
532542
From: c.From,
533543
}
@@ -546,6 +556,7 @@ func (c *GmailDraftsUpdateCmd) Run(ctx context.Context, flags *RootFlags) error
546556
"body_html_len": len(strings.TrimSpace(input.BodyHTML)),
547557
"reply_to_message_id": strings.TrimSpace(input.ReplyToMessageID),
548558
"reply_to": strings.TrimSpace(input.ReplyTo),
559+
"quote": input.Quote,
549560
"from": strings.TrimSpace(input.From),
550561
"attachments": attachPaths,
551562
}); dryRunErr != nil {
@@ -584,6 +595,9 @@ func (c *GmailDraftsUpdateCmd) Run(ctx context.Context, flags *RootFlags) error
584595
if strings.TrimSpace(replyToMessageID) == "" {
585596
replyToThreadID = existingThreadID
586597
}
598+
if c.Quote && strings.TrimSpace(replyToMessageID) == "" && strings.TrimSpace(replyToThreadID) == "" {
599+
return usage("--quote requires --reply-to-message-id or existing draft thread")
600+
}
587601

588602
input.To = to
589603
input.ReplyToThreadID = replyToThreadID

0 commit comments

Comments
 (0)