oliverthiele / ot-mailcatcher
Mailcatcher - Capture outgoing mails as files instead of sending them, review them in the backend and check them for the usual configuration mistakes.
Package info
github.com/oliverthiele/ot-mailcatcher
Type:typo3-cms-extension
pkg:composer/oliverthiele/ot-mailcatcher
Requires
- php: ^8.2
- typo3/cms-backend: ^13.4 || ^14.3
- typo3/cms-core: ^13.4 || ^14.3
- typo3/cms-reports: ^13.4 || ^14.3
- zbateson/mail-mime-parser: ^3.0
This package is auto-updated.
Last update: 2026-08-20 15:45:28 UTC
README
Captures every outgoing mail as a file instead of sending it, shows the result in a backend module, and reports the usual mail configuration mistakes in wording an editor can act on.
Features
- Nothing leaves the machine. Mails are written to
var/mailcatcher/as.emlfiles. There is no transport configured that could deliver them. - One file per mail. TYPO3's own
mboxtransport appends every message to a single file without a separator line, which leaves no reliable boundary to split them again — two mails sent within the same request then cannot be told apart. A form finisher sending a receiver notification and a sender confirmation hits exactly that case. - Rules in plain language. Ten rules report the usual mistakes, each with one sentence stating the problem and one stating what correct looks like.
- The same rules in CI. A token-protected HTTP API returns the findings as stable identifiers, so an end-to-end test can assert on them.
- Impossible to forget. While the catcher is active it says so in the system information toolbar, in the Reports module, and in a banner on every backend page.
- Locked out of Production unless explicitly allowed.
Requirements
| TYPO3 | 13.4 LTS, 14.3 LTS |
| PHP | 8.2 or newer |
Installation
composer require oliverthiele/ot-mailcatcher
Then add the transport switch at the end of config/system/additional.php —
after any block that rewrites the MAIL array, otherwise it is overwritten again:
use OliverThiele\OtMailcatcher\Mail\FileTransport; use OliverThiele\OtMailcatcher\Service\MailcatcherState; if (class_exists(MailcatcherState::class) && MailcatcherState::isActive()) { $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport'] = FileTransport::class; }
Configuration
Two environment variables, both optional:
| Variable | Effect |
|---|---|
MAILCATCHER_ALLOWED |
1 permits the catcher in the Production context. Without it, Production refuses to switch on — a forgotten catcher there stops all mail silently. |
MAILCATCHER_API_TOKEN |
Enables the test API. While empty the route answers 404 and stays completely closed. |
Switch the catcher on and off in System → Mailcatcher. The state lives in
var/mailcatcher/state.json, not in settings.php, which is version-controlled in
most projects and rewritten by TYPO3 on its own.
Usage
Backend module
System → Mailcatcher lists the captured mails with a finding count, and shows headers, findings, HTML, plain text, source and attachments per mail. The HTML part is served through its own route into a sandboxed iframe, so foreign mail content never shares the backend document.
Rules
| Identifier | Severity |
|---|---|
senderIsWebsiteVisitor |
error |
unresolvedTypo3Link |
error |
leftoverPlaceholder |
error |
emptySubject |
error |
missingReplyTo |
warning |
missingTextPart |
warning |
relativeLink |
warning |
insecureLink |
warning |
brokenEncoding |
warning |
recipientEqualsSender |
hint |
Add a project-specific rule by implementing MailCheckInterface — it is picked up
through the ot_mailcatcher.check service tag, no change to this package needed.
Test API
Requires MAILCATCHER_API_TOKEN and an active catcher. Every request carries the
token in the X-Mailcatcher-Token header.
| Endpoint | Purpose |
|---|---|
GET /_mailcatcher/api/messages |
List, optionally filtered by to and subject |
GET /_mailcatcher/api/messages/{identifier} |
One mail including text, HTML and attachment metadata |
DELETE /_mailcatcher/api/messages |
Remove all captured mails |
curl -H "X-Mailcatcher-Token: $MAILCATCHER_API_TOKEN" \
https://example.ddev.site/_mailcatcher/api/messages
Command line
typo3 mailcatcher:testmail address@example.org # sends a receiver/sender pair in one run typo3 mailcatcher:prune --days=30 # deletes captured mails beyond the retention typo3 mailcatcher:prune --days=30 --dry-run
mailcatcher:testmail deliberately sends a pair of mails in a single run: that
is the case a single-file catcher loses, so it doubles as the check that this one
does not.
License
GPL-2.0-or-later. See LICENSE.
Author
Oliver Thiele — oliver-thiele.de