Skip to content

fix: handle wrapped Gmail quote headers across all languages - #31

Open
jimmy927 wants to merge 2 commits into
alfonsrv:mainfrom
jimmy927:fix-wrapped-gmail-headers
Open

fix: handle wrapped Gmail quote headers across all languages#31
jimmy927 wants to merge 2 commits into
alfonsrv:mainfrom
jimmy927:fix-wrapped-gmail-headers

Conversation

@jimmy927

Copy link
Copy Markdown
Contributor

Gmail wraps long quote headers onto two lines, leaving the wrote-keyword alone with an optional sender + colon — same shape across locales ("On ...\nwrote:", "Den ...\nskrev:", "Am ...\nschrieb:" etc.). The per-language wrote_header patterns are line-anchored and require content between keyword and ":", so the wrap was missed in several languages (SV, DE, FR, ES). Other languages (EN, NL, IT) only worked because their patterns happened to use \s? where the wrap newline fits.

This is a Gmail-layout quirk, not a language one. Add two per-language tokens — gmail_wrap_start (the date-line prefix, e.g. "On"/"Den"/ "Am") and gmail_wrap_keyword (the verb on the wrap line, e.g. "wrote"/"skrev"/"schrieb") — alongside the existing wrote_header / from_header. EmailReplyParser.HEADER_REGEX assembles a single cross-language wrap matcher from the tokens of the configured languages, preserving the per-language opt-in. A language that doesn't set the tokens (e.g. ja, whose Gmail format is fundamentally different) simply doesn't contribute.

Adding a new language now needs only two extra lines on its dict; no edits to global constants or the parser.

The SV language pattern keeps a small relaxation for the non-wrap "Den ... skrev:" case (sender before keyword, no content between skrev and ":") — that's distinct from the wrap issue and was the original trigger for this PR.

All eight wrap-test fixtures are fully synthetic — no real names, emails, or content. 43/43 tests pass; no regressions in any language.

jimmy927 added 2 commits May 26, 2026 13:24
Gmail wraps long quote headers onto two lines, leaving the wrote-keyword
alone with an optional sender + colon — same shape across locales
("On ...\nwrote:", "Den ...\nskrev:", "Am ...\nschrieb:" etc.). The
per-language `wrote_header` patterns are line-anchored and require
content between keyword and ":", so the wrap was missed in several
languages (SV, DE, FR, ES). Other languages (EN, NL, IT) only worked
because their patterns happened to use \s? where the wrap newline fits.

This is a Gmail-layout quirk, not a language one. Add two per-language
tokens — `gmail_wrap_start` (the date-line prefix, e.g. "On"/"Den"/
"Am") and `gmail_wrap_keyword` (the verb on the wrap line, e.g.
"wrote"/"skrev"/"schrieb") — alongside the existing `wrote_header` /
`from_header`. `EmailReplyParser.HEADER_REGEX` assembles a single
cross-language wrap matcher from the tokens of the *configured*
languages, preserving the per-language opt-in. A language that doesn't
set the tokens (e.g. ja, whose Gmail format is fundamentally different)
simply doesn't contribute.

Adding a new language now needs only two extra lines on its dict; no
edits to global constants or the parser.

The SV language pattern keeps a small relaxation for the non-wrap
"Den ... skrev:" case (sender before keyword, no content between skrev
and ":") — that's distinct from the wrap issue and was the original
trigger for this PR.

All eight wrap-test fixtures are fully synthetic — no real names,
emails, or content. 43/43 tests pass; no regressions in any language.
Gmail wraps long quote headers at ~76 chars. The existing cross-language
matcher handles wrap-BEFORE-keyword (the verb falls onto its own line).
Verb-in-middle languages (sv/da/de) also see a second shape where the
wrap lands inside the recipient's <...> bracket, putting the trailing
colon alone on the next line — e.g.

  Den ... skrev Anna Andersson <
  anna@example.com>:

Add a sibling regex built from the same gmail_wrap_start/gmail_wrap_keyword
tokens for this second shape, plus sv/de fixtures + tests covering it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant