Files
mastodon_email_block/README.md
T
2026-09-08 17:18:05 +02:00

6.5 KiB

Mastodon Email Blocker

Small maintenance tool for Mastodon instances that keeps the local EmailDomainBlock table in sync with public disposable-email domain lists.

It supports two existing Mastodon layouts:

  • a normal source installation where bin/rails and bin/tootctl are available on the host;
  • an existing Docker Compose installation, where the commands are executed inside the Mastodon application container with docker compose exec.

The tool does not use the Mastodon Admin API, so importing a large list does not generate one HTTP request per domain and does not run into API rate limits.

What it changes

The blocklists are downloaded, normalized and merged. Domains already present in Mastodon are skipped; missing domains are added with Mastodon's own tootctl email-domain-blocks add command.

By default the tool also turns existing allow_with_approval email-domain records into hard deny records. Use --no-force-deny if that is not wanted.

MX records are never blocked automatically. --mx-mode report can be used for occasional DNS analysis, but the result is informational only. Shared mail infrastructure is common and blocking an MX hostname can affect unrelated, legitimate domains.

Sources

The default set is built from:

  • mehrtat/disposable-email-domain
  • FFraud-com/disposable-email-domains
  • disposable/disposable-email-domains

If a source is temporarily unavailable, the other successful sources are still used. If every source fails, the run stops before changing Mastodon.

Requirements

  • Python 3.10 or newer
  • access to the Mastodon administration commands
  • dnspython only when MX reporting is enabled

Create a virtual environment:

python3 -m venv /opt/mastodon-email-blocker/venv
/opt/mastodon-email-blocker/venv/bin/pip install -r requirements.txt

Install the script:

install -d /opt/mastodon-email-blocker
install -m 0755 bin/mastodon-email-blocker.py /opt/mastodon-email-blocker/mastodon-email-blocker.py
install -d /etc/mastodon-email-blocker /var/lib/mastodon-email-blocker
install -m 0644 config/allowlist.example.txt /etc/mastodon-email-blocker/allowlist.txt

The account running the tool must be able to run the Mastodon commands and write to /var/lib/mastodon-email-blocker.

Source installation

Run a dry run first:

/opt/mastodon-email-blocker/venv/bin/python \
  /opt/mastodon-email-blocker/mastodon-email-blocker.py \
  --backend native \
  --mastodon-dir /path/to/mastodon/live \
  --ruby-bin /path/to/ruby/bin \
  --mx-mode off \
  --dry-run

--ruby-bin can be omitted when the correct Ruby is already in PATH.

Apply the changes:

/opt/mastodon-email-blocker/venv/bin/python \
  /opt/mastodon-email-blocker/mastodon-email-blocker.py \
  --backend native \
  --mastodon-dir /path/to/mastodon/live \
  --ruby-bin /path/to/ruby/bin \
  --mx-mode off

Do not source Mastodon's .env.production from this script. Rails should load the application's production configuration in the same way it does for normal Mastodon commands.

Existing Docker Compose installation

Nothing is installed inside the Mastodon image. The Python tool runs on the Docker host and invokes Rails/tootctl in the existing application service.

For the standard Mastodon Compose layout the application service is normally named web. If the local Compose file uses another service name, pass it with --compose-service.

Dry run:

/opt/mastodon-email-blocker/venv/bin/python \
  /opt/mastodon-email-blocker/mastodon-email-blocker.py \
  --backend docker \
  --compose-dir /path/to/mastodon-compose \
  --compose-service web \
  --mx-mode off \
  --dry-run

Apply the changes:

/opt/mastodon-email-blocker/venv/bin/python \
  /opt/mastodon-email-blocker/mastodon-email-blocker.py \
  --backend docker \
  --compose-dir /path/to/mastodon-compose \
  --compose-service web \
  --mx-mode off

For installations still using the old standalone binary, use:

--compose-command "docker-compose"

The Docker user running the tool must have permission to use Docker. No database password, Mastodon secret, .env.production file or API token is read by the Python program; the existing application container already has its normal environment.

Allowlist

Put exceptions in /etc/mastodon-email-blocker/allowlist.txt, one domain per line:

example.org
mail.example.net

The allowlist only prevents the tool from adding those domains. It does not delete a block that already exists in Mastodon.

MX report

DNS/MX analysis is intentionally disabled for scheduled runs because resolving a large domain set is slow and MX providers are often shared.

Run it manually when useful:

/opt/mastodon-email-blocker/venv/bin/python \
  /opt/mastodon-email-blocker/mastodon-email-blocker.py \
  --backend native \
  --mastodon-dir /path/to/mastodon/live \
  --mx-mode report

or, for Compose:

/opt/mastodon-email-blocker/venv/bin/python \
  /opt/mastodon-email-blocker/mastodon-email-blocker.py \
  --backend docker \
  --compose-dir /path/to/mastodon-compose \
  --compose-service web \
  --mx-mode report

The report is written to /var/lib/mastodon-email-blocker/last-report.json. MX entries in that file have REPORT_ONLY status and are not sent to Mastodon.

systemd

Examples are in systemd/. Copy the matching service and the common timer, then create the corresponding environment file from config/native.env.example or config/docker.env.example.

For example:

install -m 0644 systemd/mastodon-email-blocker-docker.service /etc/systemd/system/mastodon-email-blocker.service
install -m 0644 systemd/mastodon-email-blocker.timer /etc/systemd/system/mastodon-email-blocker.timer
install -m 0644 config/docker.env.example /etc/mastodon-email-blocker/docker.env

Edit /etc/mastodon-email-blocker/docker.env, then enable the timer:

systemctl daemon-reload
systemctl enable --now mastodon-email-blocker.timer

A manual service run is useful before enabling the timer:

systemctl start mastodon-email-blocker.service
journalctl -u mastodon-email-blocker.service -n 100 --no-pager

Interrupting and re-running

A run can be interrupted with Ctrl+C. Completed batches stay in Mastodon. On the next run the existing records are read again, so already-added domains are skipped and only the remaining ones are submitted.

Files written

  • /var/lib/mastodon-email-blocker/last-report.json — last run report
  • /var/lib/mastodon-email-blocker/state.json — small state summary

The tool does not store Mastodon credentials or API tokens.