Files
mastodon_email_block/README.md
T
2026-10-02 08:03:16 +02:00

225 lines
7.8 KiB
Markdown

# 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.
After updating the domain blocks, pending registrations are checked against Mastodon's `EmailDomainBlock` matcher. Pending accounts whose email address matches a hard-blocked domain are removed using Mastodon's `DeleteAccountService`. Use `--no-cleanup-pending` to disable this behavior.
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:
```sh
python3 -m venv /opt/mastodon-email-blocker/venv
/opt/mastodon-email-blocker/venv/bin/pip install -r requirements.txt
```
Install the script:
```sh
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:
```sh
/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:
```sh
/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:
```sh
/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:
```sh
/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:
```sh
--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:
```text
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.
## Pending registrations
Pending registrations are checked after the email-domain block list has been updated.
The check uses Mastodon's own `EmailDomainBlock.block?` matcher. If a pending account uses an email address matched by a hard deny record, the account is removed through Mastodon's `DeleteAccountService`.
Only pending registrations are processed. Existing approved accounts are not removed by this cleanup.
The cleanup is enabled by default. Disable it with:
```sh
--no-cleanup-pending
```
A dry run reports matching pending registrations without deleting them:
```sh
/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 off \
--dry-run
```
The run report includes the number of pending registrations checked, matched and deleted, together with any cleanup errors.
## 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:
```sh
/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:
```sh
/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:
```sh
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:
```sh
systemctl daemon-reload
systemctl enable --now mastodon-email-blocker.timer
```
A manual service run is useful before enabling the timer:
```sh
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.
Pending registrations already removed by a completed cleanup do not require any additional state. The next run checks the current pending registrations again.
## 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.