{"record":{"id":"ead5dff55ae92e88","repo":"larksuite/cli","slug":"invalid-eml-missing-header-body-separator","errorCode":null,"errorMessage":"invalid EML: missing header/body separator","messagePattern":"invalid EML: missing header/body separator","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/mail/draft/parse.go","lineNumber":79,"sourceCode":"\t\tdecoded, err := decode(raw)\n\t\tif err == nil {\n\t\t\treturn normalizeLineEndings(decoded), nil\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"draft raw EML is not valid base64url\")\n}\n\nfunc normalizeLineEndings(in []byte) []byte {\n\tin = bytes.ReplaceAll(in, []byte(\"\\r\\n\"), []byte(\"\\n\"))\n\tin = bytes.ReplaceAll(in, []byte(\"\\r\"), []byte(\"\\n\"))\n\treturn in\n}\n\nfunc parseHeaderBlock(raw []byte) ([]Header, []byte, error) {\n\traw = normalizeLineEndings(raw)\n\tsep := bytes.Index(raw, []byte(\"\\n\\n\"))\n\tif sep < 0 {\n\t\treturn nil, nil, fmt.Errorf(\"invalid EML: missing header/body separator\")\n\t}\n\theaderLines := strings.Split(string(raw[:sep]), \"\\n\")\n\theaders := make([]Header, 0, len(headerLines))\n\tfor _, line := range headerLines {\n\t\tif strings.TrimSpace(line) == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif (strings.HasPrefix(line, \" \") || strings.HasPrefix(line, \"\\t\")) && len(headers) > 0 {\n\t\t\theaders[len(headers)-1].Value += \" \" + strings.TrimSpace(line)\n\t\t\tcontinue\n\t\t}\n\t\tname, value, ok := strings.Cut(line, \":\")\n\t\tif !ok {\n\t\t\t// Skip lines without a colon rather than failing. Some email\n\t\t\t// systems insert comment or separator lines in the header area.\n\t\t\tcontinue\n\t\t}\n\t\theaders = append(headers, Header{","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/mail/draft/parse.go#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nraw := \"From: a@b.com\\r\\nSubject: hi\\r\\nhello\"\n// after\nraw := \"From: a@b.com\\r\\nSubject: hi\\r\\n\\r\\nhello\"","handlingStrategy":"validation","validationCode":"decoded, err := decode(rawEML)\nif err == nil && !bytes.Contains(decoded, []byte(\"\\n\\n\")) && !bytes.Contains(decoded, []byte(\"\\r\\n\\r\\n\")) {\n    return errors.New(\"EML missing header/body blank line\")\n}","typeGuard":null,"tryCatchPattern":"part, err := draft.Parse(rawEML)\nif err != nil && strings.Contains(err.Error(), \"missing header/body separator\") {\n    // dump first bytes of decoded payload for diagnosis; do not retry blind\n    log.Printf(\"bad EML head: %q\", decoded[:min(200, len(decoded))])\n}","preventionTips":["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:\")"],"tags":["mail","draft","eml","malformed-input"],"backgroundTag":"malformed-email-message","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}