larksuite/cli · error

MIME nesting too deep (max %d levels)

Error message

MIME nesting too deep (max %d levels)

What it means

parsePart recurses into nested MIME entities (multipart/* and message/rfc822) and enforces maxMIMEDepth of 50 levels. Exceeding it means the message tree is pathologically nested — either genuinely crafted or cyclic/malformed. The parser aborts to bound recursion and memory rather than risk stack exhaustion.

Source

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

		Headers: append([]Header{}, partHeaders...),
	}
	if len(partHeaders) == 0 {
		part.MediaType = "text/plain"
		part.MediaParams = map[string]string{"charset": "UTF-8"}
		part.TransferEncoding = "7bit"
		part.Body = body
		part.RawEntity = append([]byte{}, body...)
		return part, nil
	}
	rawEntity := buildRawEntity(filterRawEntityHeaders(partHeaders), body)
	return parsePart(partHeaders, body, "1", rawEntity, 0)
}

const maxMIMEDepth = 50

func parsePart(headers []Header, body []byte, partID string, rawEntity []byte, depth int) (*Part, error) {
	if depth > maxMIMEDepth {
		return nil, fmt.Errorf("MIME nesting too deep (max %d levels)", maxMIMEDepth)
	}
	part := &Part{
		PartID:                partID,
		Headers:               append([]Header{}, headers...),
		MediaType:             "text/plain",
		MediaParams:           map[string]string{},
		ContentDispositionArg: map[string]string{},
		RawEntity:             append([]byte{}, rawEntity...),
	}
	if ct := headerValue(headers, "Content-Type"); ct != "" {
		mediaType, params, err := mime.ParseMediaType(ct)
		if err != nil {
			// Fallback: treat as opaque binary so the part is still accessible
			// and can round-trip through RawEntity. The original Content-Type
			// header is preserved for serialization.
			part.MediaType = "application/octet-stream"
			part.EncodingProblem = true
		} else {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Flatten the message before parsing: unwrap redundant multipart layers or re-emit the EML with a shallower structure
  2. Inspect the decoded EML's Content-Type tree to find what generates the deep nesting
  3. If legitimately deep messages are common, extract top-level parts separately instead of full recursive parse; do not raise maxMIMEDepth, it guards against stack exhaustion

Example fix

// before
part, err := draft.Parse(rawEML) // errors on deeply nested MIME
// after
if depth, ok := mimeDepthOf(rawEML); ok && depth > 50 {
    return fmt.Errorf("refusing to parse: MIME nesting depth %d exceeds limit 50", depth)
}
part, err := draft.Parse(rawEML)
Defensive patterns

Strategy: try-catch

Try / catch

part, err := draft.Parse(rawEML)
if err != nil && strings.Contains(err.Error(), "MIME nesting too deep") {
    // treat message as untrusted: quarantine, notify sender/owner, skip parsing
    return fmt.Errorf("draft rejected: malformed or malicious MIME nesting: %w", err)
}

Prevention

When it happens

Trigger: Parsing a decoded EML whose MIME part nesting exceeds 50 levels: e.g. deeply nested multipart/mixed>alternative>related>... chains or message/rfc822 attachments recursively embedding messages.

Common situations: Maliciously crafted emails (mailbomb nesting), automation that repeatedly wraps/forwards messages (each forward adds a multipart layer), or a bug in code that regenerates attachments as nested multiparts.

Related errors


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