fix: make the reply text hidden (#106) (#107)

Drew Smirnoff and Copilot created

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Change summary

config/cache.go |  1 +
main.go         | 26 +++++++++++++++++++++-----
tui/composer.go | 18 ++++++++++++++++++
tui/messages.go |  1 +
4 files changed, 41 insertions(+), 5 deletions(-)

Detailed changes

config/cache.go 🔗

@@ -237,6 +237,7 @@ type Draft struct {
 	AccountID      string    `json:"account_id"`
 	InReplyTo      string    `json:"in_reply_to,omitempty"`
 	References     []string  `json:"references,omitempty"`
+	QuotedText     string    `json:"quoted_text,omitempty"`
 	CreatedAt      time.Time `json:"created_at"`
 	UpdatedAt      time.Time `json:"updated_at"`
 }

main.go 🔗

@@ -495,20 +495,32 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 
 	case tui.ReplyToEmailMsg:
 		to := msg.Email.From
-		subject := "Re: " + msg.Email.Subject
-		body := fmt.Sprintf("\n\nOn %s, %s wrote:\n> %s", msg.Email.Date.Format("Jan 2, 2006 at 3:04 PM"), msg.Email.From, strings.ReplaceAll(msg.Email.Body, "\n", "\n> "))
+		subject := msg.Email.Subject
+		normalizedSubject := strings.ToLower(strings.TrimSpace(subject))
+		if !strings.HasPrefix(normalizedSubject, "re:") {
+			subject = "Re: " + subject
+		}
+		quotedText := fmt.Sprintf("\n\nOn %s, %s wrote:\n> %s", msg.Email.Date.Format("Jan 2, 2006 at 3:04 PM"), msg.Email.From, strings.ReplaceAll(msg.Email.Body, "\n", "\n> "))
 
+		var composer *tui.Composer
 		if m.config != nil && len(m.config.Accounts) > 0 {
 			// Use the account that received the email
 			accountID := msg.Email.AccountID
 			if accountID == "" {
 				accountID = m.config.GetFirstAccount().ID
 			}
-			composer := tui.NewComposerWithAccounts(m.config.Accounts, accountID, to, subject, body)
-			m.current = composer
+			composer = tui.NewComposerWithAccounts(m.config.Accounts, accountID, to, subject, "")
 		} else {
-			m.current = tui.NewComposer("", to, subject, body)
+			composer = tui.NewComposer("", to, subject, "")
 		}
+		composer.SetQuotedText(quotedText)
+
+		// Set reply headers
+		inReplyTo := msg.Email.MessageID
+		references := append(msg.Email.References, msg.Email.MessageID)
+		composer.SetReplyContext(inReplyTo, references)
+
+		m.current = composer
 		m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height})
 		return m, m.current.Init()
 
@@ -1024,6 +1036,10 @@ func sendEmail(account *config.Account, msg tui.SendEmailMsg) tea.Cmd {
 
 		recipients := []string{msg.To}
 		body := msg.Body
+		// Append quoted text if present (for replies)
+		if msg.QuotedText != "" {
+			body = body + msg.QuotedText
+		}
 		images := make(map[string][]byte)
 		attachments := make(map[string][]byte)
 

tui/composer.go 🔗

@@ -69,6 +69,9 @@ type Composer struct {
 	// Reply context
 	inReplyTo  string
 	references []string
+
+	// Hidden quoted text (appended to body when sending, but not shown in editor)
+	quotedText string
 }
 
 // NewComposer initializes a new composer model.
@@ -303,6 +306,9 @@ func (m *Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 						Body:           m.bodyInput.Value(),
 						AttachmentPath: m.attachmentPath,
 						AccountID:      accountID,
+						QuotedText:     m.quotedText,
+						InReplyTo:      m.inReplyTo,
+						References:     m.references,
 					}
 				}
 			}
@@ -502,6 +508,16 @@ func (m *Composer) SetReplyContext(inReplyTo string, references []string) {
 	m.references = references
 }
 
+// SetQuotedText sets the hidden quoted text that will be appended when sending.
+func (m *Composer) SetQuotedText(text string) {
+	m.quotedText = text
+}
+
+// GetQuotedText returns the hidden quoted text.
+func (m *Composer) GetQuotedText() string {
+	return m.quotedText
+}
+
 // GetInReplyTo returns the In-Reply-To header value.
 func (m *Composer) GetInReplyTo() string {
 	return m.inReplyTo
@@ -523,6 +539,7 @@ func (m *Composer) ToDraft() config.Draft {
 		AccountID:      m.GetSelectedAccountID(),
 		InReplyTo:      m.inReplyTo,
 		References:     m.references,
+		QuotedText:     m.quotedText,
 	}
 }
 
@@ -533,5 +550,6 @@ func NewComposerFromDraft(draft config.Draft, accounts []config.Account) *Compos
 	m.attachmentPath = draft.AttachmentPath
 	m.inReplyTo = draft.InReplyTo
 	m.references = draft.References
+	m.quotedText = draft.QuotedText
 	return m
 }

tui/messages.go 🔗

@@ -27,6 +27,7 @@ type SendEmailMsg struct {
 	InReplyTo      string
 	References     []string
 	AccountID      string // ID of the account to send from
+	QuotedText     string // Hidden quoted text appended when sending
 }
 
 type Credentials struct {