Self-hosted service
haileyydev/maildrop avatar
haileyydev/maildrop

Maildrop: a self-hosted disposable inbox on port 25 and 5000

✉️ A simple self hostable email service

688 stars58 forksPythonGPL-3.0

At a glance

What is it?
Maildrop is a small Python service that receives mail for any address on your domain and shows it in a web inbox, using aiosmtpd for SMTP and Flask for the interface, with an inbox file on disk rather than a database. It is deliberately aimed at people who want throwaway addresses for signups, and its configuration is a .env file with nine variables.
Who is it for?
Maildrop is worth running if you want a second address for signups on a domain you already own, because it is a single process with no database to administer, and the whole configuration surface is a .env file you can read in under a minute.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 77 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One process, one file, no database

Maildrop is described as a simple self hostable email service, and the README puts it more precisely as a self hostable and easy to use email inbox that lets you receive emails on any address on your domain.

The stated use cases are worth reading because they set the expectations. It is for people who want to easily use multiple email addresses, for signing up for services without using your main email address, and for easily creating multiple accounts on websites.

The architecture is unusually small, and the packaging explains why. The dependencies are aiosmtpd for the SMTP server, Flask for the web interface, pydantic-settings for the configuration, python-dotenv for reading the .env file, and setuptools. There is no database driver in that list, because there is no database. The mail is stored in a file, with INBOX_FILE_NAME set to inbox.json in the example configuration, and MAX_INBOX_SIZE set to 100000000, which the comment describes as 100MB in bytes and says clears the inbox when reached.

So the automatic inbox clearing, one of the checked features, is not a policy you configure but a consequence of the storage model. When the file reaches the maximum size it is cleared, which is the right behaviour for a disposable address service and the wrong behaviour for anything that wants a mailbox.

The rest of the feature list is small and specific: random email generation, custom email addresses you choose yourself, support for password protected inboxes, a clean interface, easy setup, automatic inbox clearing, and optional sending of email, which is behind its own guide in the docs folder.

The repository layout matches a small Flask service. There is a src/ directory, a pyproject.toml, a requirements.txt, a Dockerfile, an .env.example, a uv.lock and a .python-version file, plus docs/ and pictures/.

Installing is uv sync and one command

The prerequisites are Python 3 and uv, with a link to the uv installation guide, and the project uses uv as its build and run tool rather than a conventional virtualenv workflow.

The install sequence is a clone, a dependency sync and a run command. Because the SMTP server runs on port 25 by default, and that is a privileged port, the run command has to be executed as root unless you have moved the SMTP port:

bash
sudo $(which uv) run maildrop

and without the port 25 requirement it runs without root:

bash
uv run maildrop

That distinction is a real deployment decision rather than a detail of the command line. The README says Maildrop will be running on port 5000 and the SMTP server on port 25 unless configured otherwise, so the two services share a process and the web interface sits on 5000.

The console script is declared in pyproject.toml as maildrop pointing at maildrop.app:main, and the project metadata gives the name maildrop, the version 1.0.0 and requires-python of 3.14 or newer, which is a recent floor and worth checking against the Python on your server before you start.

The build backend is uv_build, pinned to a version range of 0.12.1 up to but not including 0.13.0, and the Dockerfile is correspondingly thin. It starts from the astral-sh uv image for Python 3.14 on trixie slim, copies the source into /app, runs uv sync, exposes 5000 and 25, and runs the application as its command.

Docker is the deployment the README leads with

The container route is presented first, and the command is worth reading as the deployment contract.

code
sudo docker run \
  -d \
  --restart unless-stopped \
  --name maildrop \
  -p 5000:5000 \
  -p 25:25 \
  -e DOMAIN="yourdomain.com" \
  haileyydev/maildrop:latest  

Both ports are published, the web interface and the SMTP server, and the domain is passed as an environment variable rather than baked into the image, which is what lets one image serve any deployment.

A Compose file is offered as the alternative, and it is minimal:

code
services:
  maildrop:
    image: haileyydev/maildrop:latest
    container_name: maildrop
    restart: unless-stopped
    ports:
      - "5000:5000"
      - "25:25"
    environment:
      - DOMAIN=yourdomain.com

Only the domain is passed through, because everything else has a working default in the image. The Compose file is started with sudo docker compose up -d, and the sudo is there for the port 25 binding.

The image name follows the GitHub handle of the author rather than an organisation, haileyydev/maildrop, with a latest tag. There are no GitHub releases, and the last push to the repository was on 2026-08-06, with the repository not archived, so the image and the repository are the two channels to watch for updates.

DNS is the part that decides whether mail arrives

The connection guide is four steps and the second and third are the ones that matter.

First, port 25 has to be open, because that is the port the SMTP server uses, and the README warns that some ISPs block it, so you may need a tunnel or to host Maildrop in the cloud. This is the single most common reason a self-hosted mail service receives nothing at all, and it is worth checking with the provider before anything else.

Second, create an A record for the domain you want Maildrop running on, pointing at the public IP address of the server running it. Third, create an MX record for the domain you want emails sent to, pointing at the domain where you made the A record. An MX record is what makes mail arrive at your machine, and a common mistake is to create it and forget that it points at the mail host rather than at a mail server you have not configured.

Fourth, edit the .env file and set DOMAIN to the domain you are receiving email on, and the same value is the DOMAIN environment variable in the Docker run command. The comment in the example configuration says it is the domain random emails will be generated with, so the same setting drives both the addresses you are offered and the domain the MX record points at.

The two DNS layouts are given as tables, and they are the two cases you will hit. If Maildrop runs on a different domain or subdomain from the one receiving mail, the A record points at maildrop.domain.com and the MX record points at that same host, and you would reach the interface at http://maildrop.domain.com:5000. If it runs on the same domain, both records point at the domain itself and you reach it at http://domain.com:5000. The README notes in both cases that https is preferable if you run a reverse proxy, and the Compose and configuration notes make clear that the web interface has no TLS of its own.

Nine variables, a password to change, and an optional sending path

The configuration table is short enough to be the whole story. FLASK_HOST and FLASK_PORT are the host and port for the website. SMTP_HOST and SMTP_PORT are the host and port for the SMTP server. INBOX_FILE_NAME is the file where emails are stored. MAX_INBOX_SIZE is the maximum size of the inbox. PROTECTED_ADDRESSES is a regex for inboxes that require a password. PASSWORD is the password for protected inboxes. DOMAIN is the domain used for generating email addresses.

The example environment file shows the defaults, and they are the ones to change. The protected address regex ships as ^admin.*, which protects every address beginning with admin, and the password ships as the word password, with a comment that it is the admin password needed to access protected emails and to change settings.

The comment also says the settings change is not implemented, which is worth knowing: the password gates access to protected inboxes, and the rest of that promise is not there. The regex is the flexible part, so an operator who wants a different protected set changes the pattern rather than adding accounts to a list.

Sending is a separate, optional feature. It is off by default, with ENABLE_SENDING set to false and a comment saying to set it to true to enable sending emails, and the relay block underneath holds RELAY_HOST, RELAY_PORT with a default of 2525, RELAY_USER and RELAY_PASS, the username and password to log in with marked optional. A sending guide sits in docs/SENDING.md, and the API reference is in docs/API.md, described as instructions for interacting with Maildrop through the simple JSON API.

The licence is the GNU General Public License v3.0, and the repository carries a LICENCE file at the root alongside the .env.example, the .python-version file and a .dockerignore.

Editorial conclusion

Maildrop is worth running if you want a second address for signups on a domain you already own, because it is a single process with no database to administer, and the whole configuration surface is a .env file you can read in under a minute. It is the wrong tool if you need message history beyond the inbox limit, because the inbox is a file that is cleared when it reaches its maximum size, and it is the wrong tool if you cannot run a service on port 25, since inbound SMTP on the standard port is the one hard requirement. Before you deploy it, verify three things yourself: that your hosting provider does not block port 25, which is the most common reason this kind of service fails to receive anything, that the A and MX records you create point where you think they do, since the MX record is what makes mail arrive at all, and that the default protected address regex and password are changed, because the example configuration ships a password of password and a regex matching any address starting with admin.

Frequently asked questions

What is Maildrop?

It is a self hostable email service and inbox that receives mail for any address on your domain, aimed at people who want multiple addresses, who want to sign up for services without their main address, and who create multiple accounts on websites. It runs an SMTP server on port 25 and a web interface on port 5000.

How do I install and run Maildrop?

Clone the repository, run uv sync to install the dependencies, then run the application. Because the SMTP server uses port 25 by default it must be run as root, with sudo $(which uv) run maildrop, and without that port requirement plain uv run maildrop works. The console script is maildrop, pointing at maildrop.app:main.

What DNS records does Maildrop need?

An A record for the domain the service runs on, pointing at the public IP of the server, and an MX record for the domain you want to receive mail on, pointing at the domain where you made the A record. You also set DOMAIN in the .env file or the environment variable to the receiving domain.

Where does Maildrop store the mail?

In a file, with INBOX_FILE_NAME defaulting to inbox.json, and there is no database. MAX_INBOX_SIZE defaults to 100000000 bytes, described as 100MB, and the inbox is cleared when it is reached, which is why the service is aimed at disposable addresses.

How do password protected inboxes work in Maildrop?

PROTECTED_ADDRESSES is a regex, defaulting to ^admin.*, that selects which inboxes require a password, and PASSWORD holds the password for those inboxes. The example configuration ships the password as password, so it should be changed before deployment.

Official sources

  1. haileyydev/maildrop on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/haileyydev-maildrop.svg)](https://hysenlabs.com/projects/haileyydev-maildrop)