diff --git a/docs/keybindings.md b/docs/keybindings.md index 17b9eee..cf513ce 100644 --- a/docs/keybindings.md +++ b/docs/keybindings.md @@ -113,6 +113,7 @@ Press `?` inside neomd to open the interactive help overlay. Start typing to fil | `R` | reload / refresh folder | | `r` | reply (from inbox or reader) | | `ctrl+r` | reply-all — reply to sender + all CC recipients (from inbox or reader) | +| `ctrl+e` | react with emoji (from inbox or reader) | | `f` | forward email (from reader or inbox) | | `T` | show full conversation thread across folders (from inbox or reader) | | `c` | compose new email | diff --git a/internal/editor/editor.go b/internal/editor/editor.go index 9cf87a1..967ff3b 100644 --- a/internal/editor/editor.go +++ b/internal/editor/editor.go @@ -129,6 +129,19 @@ func ForwardPrelude(subject, from, originalFrom, originalDate, originalTo, origi return s } +// ReactionBody builds the plain text body for an emoji reaction. +func ReactionBody(emoji, fromName string) string { + return fmt.Sprintf("%s\n\n%s reacted via neomd (https://neomd.ssp.sh)\n", emoji, fromName) +} + +// ReactionBodyHTML builds the HTML body for an emoji reaction. +func ReactionBodyHTML(emoji, fromName string) string { + return fmt.Sprintf(`
+%s reacted via neomd +
`, emoji, fromName) +} + // ParseHeaders scans raw editor content for # [neomd: key: value] lines and // returns the extracted to, cc, bcc, from, subject values and the remaining body // (with header lines stripped). Any field not found is returned as "". diff --git a/internal/imap/client.go b/internal/imap/client.go index c5edfa7..efa79dc 100644 --- a/internal/imap/client.go +++ b/internal/imap/client.go @@ -49,6 +49,7 @@ type Email struct { HasAttachment bool // true if BODYSTRUCTURE contains an attachment part MessageID string // Message-ID from envelope (for threading) InReplyTo string // first In-Reply-To message ID (for threading) + References string // References header (space-separated Message-IDs for threading) } // Config holds connection parameters. @@ -325,6 +326,8 @@ func (c *Client) FetchHeaders(ctx context.Context, folder string, n int) ([]Emai if len(m.Envelope.InReplyTo) > 0 { e.InReplyTo = m.Envelope.InReplyTo[0] } + // Note: References header is fetched when the body is loaded (FetchBody) + // because it's not available in the IMAP Envelope structure. } e.Size = uint32(m.RFC822Size) e.HasAttachment = hasAttachment(m.BodyStructure) diff --git a/internal/smtp/sender.go b/internal/smtp/sender.go index d7772f4..5d48dd8 100644 --- a/internal/smtp/sender.go +++ b/internal/smtp/sender.go @@ -249,6 +249,12 @@ func sendSTARTTLSWithConfig(addr, host string, tlsCfg *tls.Config, auth smtp.Aut // otherwise the structure is unchanged (multipart/alternative only). // htmlSignature, if non-empty, is injected before the closing