---
tags:
 - meta
---

# import_headers

```
message:import_headers(SPECS)
```

{{since('2026.05.12-a6845223')}}

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](import_x_headers.md). 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](import_x_headers.md))
    * `"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:

```lua
msg:import_headers {
  { name = 'X-*', remove = true },
}
```

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

```lua
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:

```lua
msg:import_headers {
  { name = 'X-Campaign-Id', target = 'campaign_id' },
  { name = 'X-*' },
}
```

Use a different naming style:

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

## See Also

* [message:import_x_headers](import_x_headers.md)
* [message:remove_x_headers](remove_x_headers.md)
