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.

Maintainers

Package info

github.com/oliverthiele/ot-mailcatcher

Homepage

Type:typo3-cms-extension

pkg:composer/oliverthiele/ot-mailcatcher

Transparency log

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.2 2026-08-20 15:45 UTC

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.

TYPO3 Packagist Version PHP License Changelog

Features

  • Nothing leaves the machine. Mails are written to var/mailcatcher/ as .eml files. There is no transport configured that could deliver them.
  • One file per mail. TYPO3's own mbox transport 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