> ## Documentation Index
> Fetch the complete documentation index at: https://docs.libredesk.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Email sender verification

> When an email sender's identity can be trusted by AI custom tools

When the AI agent calls a custom tool, it sends the contact's identity as HTTP headers so the tool can act on the right account:

| Header                            | Value                                 |
| --------------------------------- | ------------------------------------- |
| `X-Libredesk-Contact-External-Id` | The contact's external ID, when known |
| `X-Libredesk-Contact-Email`       | The sender's email address            |
| `X-Libredesk-Contact-Verified`    | `true` or `false`                     |

`X-Libredesk-Contact-Verified` tells the tool whether Libredesk considers the sender's identity trustworthy. The identity headers are always sent; the flag tells the tool whether to act on them.

## Why email needs this

On the livechat widget, identity comes from a signed login (JWT): your site authenticated the user and passed that identity to Libredesk. That identity is trustworthy.

Email is different. Libredesk reads mail from a mailbox over IMAP and sees whatever landed in the inbox. The `From` address on an email is not, by itself, proof of who sent it. Anyone can put `From: customer@example.com` on a message. If a custom tool trusted that address blindly, someone could email support pretending to be a customer and have the tool act on that customer's account.

## What Libredesk can and cannot check

Libredesk sits **downstream** of your mail server. It does not receive mail over SMTP and does not evaluate SPF, DKIM, or DMARC itself. Those checks happen at your mail server when the message arrives, before Libredesk polls the mailbox.

It also cannot reliably read the result from inside the mailbox. Mail servers record their verdict in an `Authentication-Results` header, but a sender can forge that header; only the receiving mail server can strip a forged copy, and Libredesk cannot tell a genuine header from a fake one after the fact. Trusting it would reintroduce the spoofing problem.

So email verification rests on two facts, one you assert and one Libredesk checks:

1. **Your mail server rejects or quarantines mail that fails DMARC.** Libredesk cannot detect this, so you assert it with the inbox setting below. Gmail and Google Workspace do this by default.
2. **The sender's domain publishes an enforcing DMARC policy.** Libredesk checks this by looking up the sender domain's DMARC record in DNS when the message arrives.

When both hold, a spoofed message from that sender's domain would have been rejected or quarantined by your mail server before it reached the inbox. A message that *did* arrive is therefore genuinely from that sender, and Libredesk marks it verified. If either is false, email is sent to tools as unverified. The AI still answers the customer, it just does not confirm the identity.

## The inbox setting

Each email inbox has a setting:

**Upstream server enforces DMARC** (default: off)

Turn this on only if the mail server behind this mailbox rejects or quarantines messages that fail DMARC. Gmail and Google Workspace do; a self-managed mail server does so only when configured to.

| Setting | Behavior for email                                                                       |
| ------- | ---------------------------------------------------------------------------------------- |
| **On**  | A reply is marked verified when the sender's domain also enforces DMARC. Both must hold. |
| **Off** | Email replies are always sent to tools as unverified.                                    |

Leave it off if you are unsure. With it off the AI agent still works; tools that require a verified identity simply decline to act on email. Livechat contacts are unaffected.

### What counts as an enforcing policy

Libredesk looks up the DMARC record at `_dmarc.<sender-domain>`. A domain is treated as enforcing when:

* its policy is `p=reject` or `p=quarantine`, and
* the policy applies to all mail (`pct` is 100 or absent).

For a subdomain sender with no record of its own, Libredesk falls back to the organizational domain's record and honors its subdomain policy (`sp=`). A policy of `p=none`, a partial rollout (`pct` below 100), a missing record, or a lookup failure all result in the sender being treated as unverified.

This checks the sender domain's *published policy*, not a per-message DMARC result. The pass/fail decision is made by your mail server, which is why the inbox setting is required.

## For custom tool authors

<Warning>
  Any tool that performs an action on a customer's account must check `X-Libredesk-Contact-Verified` and refuse to act when it is not `true`.
</Warning>

Libredesk always sends the identity headers and guarantees the verified flag is honest. It does not withhold the identity from a tool. Whether to trust that identity is the tool's decision, because the tool is the code that acts.

```python theme={null}
if request.headers.get("X-Libredesk-Contact-Verified") != "true":
    # Do not act on the account. Return a message the AI can relay,
    # e.g. ask the customer to reach you through a verified channel.
    return {"error": "unverified sender"}

external_id = request.headers["X-Libredesk-Contact-External-Id"]
# ... perform the action for external_id ...
```

Read-only tools that do not act on a specific account can ignore the flag. Any tool that changes state, reveals private data, or acts on someone's behalf should treat `X-Libredesk-Contact-Verified: false` as "do not proceed".

## Summary

| Channel  | Verified when                                                      |
| -------- | ------------------------------------------------------------------ |
| Livechat | The contact logged in with a signed identity (JWT)                 |
| Email    | The inbox setting is on **and** the sender's domain enforces DMARC |
