Files
kumomta/docs/reference/message/import_headers.md
T
Wez Furlong ee1e5b980e message: add msg:import_headers, a flexible alternative to import_x_headers
import_headers takes an array of per-spec option tables, each describing
how a single header name or pattern should be imported into the message
metadata. Compared to import_x_headers it adds:

 * Trailing-`*` wildcard patterns (e.g. `X-*`) alongside exact names.
   Bare/leading/interior wildcards are rejected at compile time.
 * `match` of `first`, `last` (default), or `all`. `all` captures every
   matching header instance as an array of strings; the others capture
   a string. Specs that produce no matches write nothing.
 * `transform` selects the metadata key style: `snake_case` (default,
   matches the existing import_x_headers behavior), `kebab_case`,
   `camel_case`, or `pascal_case`. Header matching itself is always
   case-insensitive.
 * `target` overrides the metadata key for exact-name specs.
 * `remove` strips the matched headers from the message body in a
   single follow-up pass.

When more than one spec could match a header, the first matching spec
wins, so callers can place specific rules ahead of a wildcard catch-all.

import_x_headers now delegates to import_headers, so its behavior is
unchanged and the two share a single implementation.

retain_headers now passes the header index alongside the &Header to its
closure, which import_headers uses for its post-pass removal step
instead of tracking a parallel counter. Existing callers that don't
need the index ignore it with `_`.

Closes: #515
2026-05-06 16:30:36 +01:00

3.4 KiB

tags
tags
meta

import_headers

message:import_headers(SPECS)

{{since('dev')}}

Iterates the headers of the message, importing matching header values into the message metadata. SPECS is an array of tables, one per header name or pattern, each describing how that header should be matched, named in the metadata, and optionally removed.

This is a more flexible alternative to message:import_x_headers. The same call can be used to import multiple distinct headers with different rules, and can also be used to strip the matched headers from the message body in a single pass.

Spec fields

Each entry in SPECS accepts the following fields:

  • name (required, string) — the header name to match.

    Matching is always case-insensitive. The pattern can be either a precise header name (e.g. "Subject") or a name with a single trailing * wildcard (e.g. "X-*"), which matches any header whose name begins with the literal portion of the pattern. Bare *, leading wildcards, and interior wildcards are not supported.

  • match (optional, string, default "last") — which matching headers to capture:

    • "first" — capture the first matching header value as a string.
    • "last" — capture the last matching header value as a string.
    • "all" — capture every matching header value as an array of strings.
  • transform (optional, string, default "snake_case") — how to derive the metadata key from the matched header name. All transforms produce a deterministic key. Examples below assume a matched header named X-Campaign-Id:

    • "snake_case"x_campaign_id (matches the transform performed by message:import_x_headers)
    • "kebab_case"x-campaign-id
    • "camel_case"xCampaignId
    • "pascal_case"XCampaignId
  • target (optional, string) — explicitly set the metadata key to use, bypassing transform. Only valid when name is a precise header name; using target with a wildcard pattern produces an error.

  • remove (optional, bool, default false) — when true, the matched header instances are removed from the message body after their values have been captured.

If a spec produces no matches, no metadata is written for it (including for match = "all", which writes nothing rather than an empty array).

When more than one spec could match a header, the first spec in SPECS that matches wins. This lets you place a precise rule for a specific header in front of a broader wildcard catch-all.

Examples

Import all X- headers into metadata, and strip them from the message:

msg:import_headers {
  { name = "X-*", remove = true },
}

Capture every Received: header as an array, while also lifting the subject:

msg:import_headers {
  { name = "Received", match = "all" },
  { name = "Subject" },
}

Treat one specific header specially, while still importing the rest of the X- headers with the default transform:

msg:import_headers {
  { name = "X-Campaign-Id", target = "campaign_id" },
  { name = "X-*" },
}

Use a different naming style:

msg:import_headers {
  { name = "X-*", transform = "camel_case" },
}
-- X-Campaign-Id is captured as `xCampaignId`

See Also