# Email Spam Filter

The Email Spam Filter processes inbound email in EML (RFC 822) format through Sentinel's HTTP API and returns both the parsed message and a full classification report — a fit for SaaS apps, helpdesks, contact forms, or anything else that needs to screen inbound mail.

> **Note:**
>
> Sentinel doesn't include an SMTP server — you handle email reception yourself (fetch from your mail server directly, or use a provider like AWS SES for inbound mail) and forward the raw EML to Sentinel's API.

## How it works

Rather than a Bayesian classifier or a static blacklist, scoring combines several layers:

1. **Content analysis** — structural red flags in the message.
2. **Signature verification** — ARC, DKIM, and SPF authentication.
3. **NLP** — the same language analysis behind the [Classifier](/docs/sentinel/features/classifier/), applied to the email body.
4. **Phishing detection** — URLs checked against [Phishing Detection](/docs/sentinel/features/phishing-detection/)'s continuously-updated feed.
5. **Attachment handling** — attachments can be safely extracted and uploaded to S3/Azure Blob storage instead of returned inline.

A 20KB email typically processes in around 15ms.

## Setup

1. Finish installing Sentinel.
2. Create an [API Key](/docs/sentinel/configure/api-keys/) on a Security Group with **Restricted** access — this isn't a public endpoint.

## Submitting an email

```
POST /v1/eml
Content-Type: application/octet-stream
Authorization: Bearer {API_KEY}

[raw EML file as the request body]
```

Optional request headers:

| Header | Purpose | Default |
|---|---|---|
| `X-Authenticate` | Run ARC/DKIM/SPF verification (requires DNS lookups) | `false` |
| `X-Attachments-Upload` | Upload attachments to storage instead of returning them inline | `false` |
| `X-Attachments-Size-Limit` | Max attachment size, bytes | `5000000` |
| `X-Disable-Rules` | Comma-separated list of rules to skip | — |
| `X-Similarity-Groups` | [Training data groups](/docs/sentinel/features/similarity-training-data/) to match the body against | — |
| `X-Mail-From` | Sender from the SMTP `MAIL FROM` command, if you have it | — |
| `X-Smtp-Ip` | The relaying SMTP server's IP | — |
| `X-Smtp-Helo` | The relay's HELO/EHLO hostname | — |
| `X-Smtp-Mta` | The server that performed authentication | — |
| `X-Trust-Authentication` | Trust an existing `Authentication-Results` header instead of re-verifying | `true` |

### Response

```json
{
"authentication": {
"ARC": { "result": "pass", "comment": "..." },
"DKIM": [{ "result": "neutral", "signingDomain": "..." }],
"SPF": { "result": "pass", "comment": "..." }
},
"classification": {
"classification": "GOOD",
"score": 0.5,
"email": { "score": 0, "rules": {}, "triggeredRules": [] },
"text": { "score": 1, "rules": {}, "triggeredRules": [] }
},
"mail": {
"from": [{ "address": "...", "name": "..." }],
"to": [{ "address": "...", "name": "..." }],
"subject": "...",
"text": "...",
"html": "...",
"attachments": [],
"headers": []
},
"rules": {
"ARC": { "score": null },
"DKIM": { "score": null },
"SPF": { "score": null },
"FROM_SPOOFING": { "score": 0 },
"REPLY_TO_SPOOFING": { "score": 0 },
"CLASSIFICATION": { "score": 0.5 },
"NO_SUBJECT": { "score": 0 },
"NO_TEXT": { "score": 0 },
"UNDISCLOSED_RECIPIENTS": { "score": 1 },
"DELIVERED_TO_MISMATCH": { "score": 0 }
},
"score": 1.5,
"spam": false,
"time": 5.189
}
```

A total `score` of 2 or higher is treated as spam.

## Email-specific rules

| Rule | Flags |
|---|---|
| `FROM_SPOOFING` | Sender display name doesn't match the actual address — a common phishing indicator. |
| `REPLY_TO_SPOOFING` | `Reply-To` differs from the sender address — also a common phishing indicator. |
| `ARC` / `DKIM` / `SPF` | Authentication failures (only checked with `X-Authenticate: true`). |
| `NO_SUBJECT` / `NO_TEXT` | Missing subject or body content. |
| `UNDISCLOSED_RECIPIENTS` | No valid `To` address. |
| `DELIVERED_TO_MISMATCH` | `Delivered-To` doesn't match the `To` header. |

## Attachments

Attachments are returned Base64-encoded inline by default. With `X-Attachments-Upload: true`, they're uploaded to your configured [storage provider](/docs/sentinel/operations/storage-providers/) instead, and can be retrieved later via `GET /v1/blobs/{key}`.

## Configuration

| Variable | Default | Purpose |
|---|---|---|
| `EML_BODY_LIMIT` | `5MB` | Maximum size of an incoming EML file. |

## Related

- [Phishing Detection](/docs/sentinel/features/phishing-detection/) — the URL feed this cross-references.
- [Classifier](/docs/sentinel/features/classifier/) — shared NLP scoring engine and rule format.
- [Similarity & Training Data](/docs/sentinel/features/similarity-training-data/) — `X-Similarity-Groups`.
- [Storage Providers](/docs/sentinel/operations/storage-providers/) — where uploaded attachments go.
- [ENV Variables](/docs/sentinel/operations/env-variables/#email--smtp)
