larksuite/cli · error

draft raw EML is not valid base64url

Error message

draft raw EML is not valid base64url

What it means

decodeRawEML expects the EML as base64url text (it tries standard and raw variants of URL and Std alphabets, then falls back to treating input as raw EML bytes elsewhere). If every decoder fails, the input is neither valid base64 nor was it pre-decoded. The error aggregates all decoder failures into one message.

Source

Thrown at shortcuts/mail/draft/parse.go:66

	if raw == "" {
		return nil, fmt.Errorf("draft raw EML is empty")
	}
	if len(raw) > maxRawEMLSize {
		return nil, fmt.Errorf("draft raw EML is too large (%d bytes, max %d)", len(raw), maxRawEMLSize)
	}
	decoders := []func(string) ([]byte, error){
		base64.URLEncoding.DecodeString,
		base64.RawURLEncoding.DecodeString,
		base64.StdEncoding.DecodeString,
		base64.RawStdEncoding.DecodeString,
	}
	for _, decode := range decoders {
		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) == "" {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Ensure the input is base64url-encoded (or try base64.StdEncoding first to check); decode/encode explicitly at your boundary
  2. Strip whitespace/newlines before encoding: base64.URLEncoding.EncodeString([]byte(emlText))
  3. Log decode errors per-variant locally to identify alphabet/padding issues

Example fix

// before
part, err := draft.Parse(emlPlainText)
// after
encoded := base64.URLEncoding.EncodeString([]byte(emlPlainText))
part, err := draft.Parse(encoded)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := base64.StdEncoding.DecodeString(strings.TrimSpace(rawEML)); err != nil {
    if _, err2 := base64.RawURLEncoding.DecodeString(rawEML); err2 != nil {
        return fmt.Errorf("raw EML is not base64: encode it before calling Parse")
    }
}

Type guard

func isBase64(s string) bool {
    for _, enc := range []*base64.Encoding{
        base64.URLEncoding, base64.RawURLEncoding,
        base64.StdEncoding, base64.RawStdEncoding,
    } {
        if _, err := enc.DecodeString(strings.TrimSpace(s)); err == nil {
            return true
        }
    }
    return false
}

Try / catch

part, err := draft.Parse(rawEML)
if err != nil && strings.Contains(err.Error(), "not valid base64url") {
    encoded := base64.URLEncoding.EncodeString([]byte(rawEML))
    part, err = draft.Parse(encoded)
}

Prevention

When it happens

Trigger: Passing already-decoded EML text (starting with 'Message-ID:' etc.) directly to Parse, passing base64 with an unsupported alphabet/whitespace/URL-safe mixing beyond the four decoders, or truncated base64 with wrong padding.

Common situations: Confusing the raw EML body with its encoded form after an API change, copying base64 with line breaks the decoder cannot tolerate in that variant, or double-encoding/decoding in a pipeline.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/d68851c97714f4f1. Report an issue: GitHub.