larksuite/cli · error
invalid EML: missing header/body separator
Error message
invalid EML: missing header/body separator
What it means
parseHeaderBlock splits the decoded EML at the first blank line (\n\n) separating headers from body. If no blank line exists, the bytes are not shaped like an RFC 5322 message (headers block followed by an empty line). The error indicates malformed or truncated EML content rather than a parser bug.
Source
Thrown at shortcuts/mail/draft/parse.go:79
decoded, err := decode(raw)
if err == nil {
return normalizeLineEndings(decoded), nil
}
}
return nil, fmt.Errorf("draft raw EML is not valid base64url")
}
func normalizeLineEndings(in []byte) []byte {
in = bytes.ReplaceAll(in, []byte("\r\n"), []byte("\n"))
in = bytes.ReplaceAll(in, []byte("\r"), []byte("\n"))
return in
}
func parseHeaderBlock(raw []byte) ([]Header, []byte, error) {
raw = normalizeLineEndings(raw)
sep := bytes.Index(raw, []byte("\n\n"))
if sep < 0 {
return nil, nil, fmt.Errorf("invalid EML: missing header/body separator")
}
headerLines := strings.Split(string(raw[:sep]), "\n")
headers := make([]Header, 0, len(headerLines))
for _, line := range headerLines {
if strings.TrimSpace(line) == "" {
continue
}
if (strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t")) && len(headers) > 0 {
headers[len(headers)-1].Value += " " + strings.TrimSpace(line)
continue
}
name, value, ok := strings.Cut(line, ":")
if !ok {
// Skip lines without a colon rather than failing. Some email
// systems insert comment or separator lines in the header area.
continue
}
headers = append(headers, Header{View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Ensure the EML has a blank line (\\r\\n\\r\\n or \\n\\n) between the header block and the body
- Verify the payload decodes to real EML text (print the first ~200 bytes) before parsing
- If synthesizing EML, append \\r\\n\\r\\n after the last header before the body
Example fix
// before raw := "From: a@b.com\r\nSubject: hi\r\nhello" // after raw := "From: a@b.com\r\nSubject: hi\r\n\r\nhello"
Defensive patterns
Strategy: validation
Validate before calling
decoded, err := decode(rawEML)
if err == nil && !bytes.Contains(decoded, []byte("\n\n")) && !bytes.Contains(decoded, []byte("\r\n\r\n")) {
return errors.New("EML missing header/body blank line")
} Try / catch
part, err := draft.Parse(rawEML)
if err != nil && strings.Contains(err.Error(), "missing header/body separator") {
// dump first bytes of decoded payload for diagnosis; do not retry blind
log.Printf("bad EML head: %q", decoded[:min(200, len(decoded))])
} Prevention
- Keep the blank line between headers and body when generating or editing EML text
- Avoid regex/text cleaners that strip empty lines from message content
- Sanity-check decoded payloads start with header-like lines (e.g. "From:", "Message-ID:")
When it happens
Trigger: Calling Parse with decoded bytes that have headers but no blank line before the body, empty body region glued directly to headers, a truncated EML, or binary garbage with no MIME/RFC822 structure.
Common situations: Manually constructing EML strings and forgetting the blank line, stripping blank lines with a text cleaner/regex, downloading a partial draft, or decoding a payload that was not actually an EML.
Related errors
- add_attachment requires path
- remove_attachment requires target with at least one of part_
- add_inline requires path
- add_inline requires cid
- replace_inline requires target with at least one of part_id
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/ead5dff55ae92e88.
Report an issue: GitHub.