# 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: ```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. ## 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. ## 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.