feat(gmail): add --body-format flag to messages search
Supports "text" (default, existing behavior) and "html" to prefer the HTML MIME part over plaintext. Useful for newsletter ingestion where the HTML body contains the rich formatted content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> (cherry picked from commit cb5499ed7b4d20a863de1aef07c58c94ecd9a9fe)
This commit is contained in:
parent
3236577249
commit
d08771e66d
44
.byline/commits/4a477a05f.json
Normal file
44
.byline/commits/4a477a05f.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"sha": "4a477a05f2f16b649211e2c77ad9e1c8c7f6e777",
|
||||
"shortSha": "4a477a05f",
|
||||
"parentSha": "0d0d95a00c41d5f05ecadf22f44788bd5163b2fc",
|
||||
"timestamp": "2026-04-21T21:42:31-04:00",
|
||||
"message": "Add byline commit classification cache files",
|
||||
"files": {
|
||||
".byline/commits/0d0d95a00.json": {
|
||||
"path": ".byline/commits/0d0d95a00.json",
|
||||
"summary": {
|
||||
"mine": 2214,
|
||||
"machine": 0,
|
||||
"ours": 0
|
||||
},
|
||||
"segments": []
|
||||
},
|
||||
".byline/commits/c9f2e83f2.json": {
|
||||
"path": ".byline/commits/c9f2e83f2.json",
|
||||
"summary": {
|
||||
"mine": 1379,
|
||||
"machine": 0,
|
||||
"ours": 0
|
||||
},
|
||||
"segments": []
|
||||
}
|
||||
},
|
||||
"totals": {
|
||||
"mine": 3593,
|
||||
"machine": 0,
|
||||
"ours": 0,
|
||||
"percent": {
|
||||
"mine": 100,
|
||||
"machine": 0,
|
||||
"ours": 0
|
||||
}
|
||||
},
|
||||
"sessions": [],
|
||||
"meta": {
|
||||
"analyzedAt": "2026-04-22T01:42:31.526Z",
|
||||
"version": "0.2.0",
|
||||
"retroactive": false,
|
||||
"confidence": 1
|
||||
}
|
||||
}
|
||||
@ -28,6 +28,7 @@ type GmailMessagesSearchCmd struct {
|
||||
Timezone string `name:"timezone" short:"z" help:"Output timezone (IANA name, e.g. America/New_York, UTC). Default: local"`
|
||||
Local bool `name:"local" help:"Use local timezone (default behavior, useful to override --timezone)"`
|
||||
IncludeBody bool `name:"include-body" help:"Include decoded message body (JSON is full; text output is truncated)"`
|
||||
BodyFormat string `name:"body-format" help:"Body format preference: text (default) or html" default:"text" enum:"text,html"`
|
||||
Full bool `name:"full" help:"Show full message bodies without truncation (implies --include-body)"`
|
||||
}
|
||||
|
||||
@ -88,7 +89,7 @@ func (c *GmailMessagesSearchCmd) Run(ctx context.Context, flags *RootFlags) erro
|
||||
return err
|
||||
}
|
||||
|
||||
items, err := fetchMessageDetails(ctx, svc, messages, idToName, loc, c.IncludeBody)
|
||||
items, err := fetchMessageDetails(ctx, svc, messages, idToName, loc, c.IncludeBody, c.BodyFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -200,7 +201,8 @@ type messageItem struct {
|
||||
Body string `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
func fetchMessageDetails(ctx context.Context, svc *gmail.Service, messages []*gmail.Message, idToName map[string]string, loc *time.Location, includeBody bool) ([]messageItem, error) {
|
||||
func fetchMessageDetails(ctx context.Context, svc *gmail.Service, messages []*gmail.Message, idToName map[string]string, loc *time.Location, includeBody bool, bodyFormat ...string) ([]messageItem, error) {
|
||||
preferHTML := len(bodyFormat) > 0 && bodyFormat[0] == "html"
|
||||
if len(messages) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@ -257,7 +259,11 @@ func fetchMessageDetails(ctx context.Context, svc *gmail.Service, messages []*gm
|
||||
item.Subject = sanitizeTab(headerValue(msg.Payload, "Subject"))
|
||||
item.Date = formatGmailDateInLocation(headerValue(msg.Payload, "Date"), loc)
|
||||
if includeBody {
|
||||
item.Body = bestBodyText(msg.Payload)
|
||||
if preferHTML {
|
||||
item.Body = bestBodyHTML(msg.Payload)
|
||||
} else {
|
||||
item.Body = bestBodyText(msg.Payload)
|
||||
}
|
||||
}
|
||||
|
||||
if len(msg.LabelIds) > 0 {
|
||||
|
||||
@ -377,6 +377,18 @@ func bestBodyText(p *gmail.MessagePart) string {
|
||||
return html
|
||||
}
|
||||
|
||||
func bestBodyHTML(p *gmail.MessagePart) string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
html := findPartBody(p, "text/html")
|
||||
if html != "" {
|
||||
return html
|
||||
}
|
||||
plain := findPartBody(p, "text/plain")
|
||||
return plain
|
||||
}
|
||||
|
||||
func bestBodyForDisplay(p *gmail.MessagePart) (string, bool) {
|
||||
if p == nil {
|
||||
return "", false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user