Skip to main content

Submit an email

Use POST /v1/email-analyses with the complete email as the binary request body.

Required headers

HeaderContract
X-API-KeyCredential issued by Hermes; never place it in a URL
Idempotency-Key8–128 safe ASCII characters for one logical submission
Content-Typemessage/rfc822; media-type parameters are accepted

X-Request-ID is optional. Supply 8–80 safe, non-secret characters matching ^[A-Za-z0-9][A-Za-z0-9._:-]{7,79}$. Hermes replaces an invalid value with a generated identifier and echoes the accepted identifier in the response header and body.

Omit Content-Encoding or send identity. Compressed bodies are rejected.

Preserve the original bytes

Read the .eml as bytes once and reuse that same byte buffer for retries. Include original headers, MIME boundaries, bodies, and attachments. Do not:

  • convert the message to JSON;
  • send multipart form data;
  • extract only visible text;
  • base64-encode the whole request;
  • silently truncate headers or remove attachments.
IDEMPOTENCY_KEY="submit-$(uuidgen)"
curl --request POST \
"$HERMES_API_BASE_URL/v1/email-analyses" \
--header "X-API-Key: $HERMES_API_KEY" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "Content-Type: message/rfc822" \
--data-binary @message.eml

Processing limits

LimitMaximum
Complete EML body10,485,760 bytes (10 MiB)
Header block262,144 bytes (256 KiB)
Header count across the parsed message500
One logical header65,536 bytes (64 KiB)
MIME parts200
MIME nesting depth20
Attachments50
Aggregate decoded part data10,485,760 bytes (10 MiB)

Exceeding the complete-body limit returns 413 payload_too_large. Structurally excessive messages return 422 email_too_complex.

Minimum usable message

Hermes rejects an empty body, NUL bytes, or input without an analyzable RFC 5322 header/body section. A message must contain recognizable email headers and a body. Some imperfect but tolerably parseable MIME is accepted with malformed_message_accepted; invalid UTF-8 replacement is reported as invalid_utf8_replaced.

Synchronous completion

The server's current wall-clock processing budget defaults to 45 seconds and cannot be configured above 120 seconds. This is a processing bound, not a latency or availability SLA. Set a per-attempt client timeout above the server ceiling and also enforce a finite overall retry deadline.

If a client timeout or network interruption leaves the outcome unknown, retry with the same idempotency key and exactly the same bytes. Do not create a new key merely because no response arrived.