SkillAgentSearch skills...

Mailwhale

🐳 A bring-your-own-SMTP-server mail relay with REST API and web UI

Install / Use

/learn @muety/Mailwhale
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Please note: as of Dec 2023, MailWhale is depcreated and not being actively maintained anymore. Please check out some of the alternatives mentioned below.

<p align="center"> <img src="assets/logo.svg" width="275px"> </p> <h1 align="center">MailWhale</h1> <h3 align="center">A <i>bring-your-own-SMTP-server</i> mail relay</h3> <p align="center"> <img src="https://badges.fw-web.space/github/license/muety/mailwhale"> <a href="mailto:ferdinand@muetsch.io?subject=Thanks for creating MailWhale" target="_blank"><img src="https://badges.fw-web.space/badge/say%20thanks-%F0%9F%99%8F-%23159CE4"></a> <a href="https://wakapi.dev" target="_blank"><img src="https://badges.fw-web.space/endpoint?url=https://wakapi.dev/api/compat/shields/v1/n1try/interval:any/project:mailwhale&color=blue"></a> </p>

📄 Description

As a developer, chances are high that at some point you need to teach your application how to send mails. Essentially, there are two options. Either you use a professional mail sending service or you include an SMTP client library to your software and plug your own mail server.

Think of MailWhale like Mailgun, SendGrid or SMTPeter, but open source and self-hosted. Or like Postal or Cuttlefish, but less bloated and without running its own, internal SMTP server.

However, if you want the best of both worlds – that is, send mails via simple HTTP calls and with no extra complexity, but still use your own infrastructure – you may want to go with ✉️🐳.

You get a simple REST API, which you can call to send out e-mail. You can plug your self-hosted SMTP server, as well as Google Mail or literally any other e-mail provider.

Stay tuned, there is a lot more to come.

🚧 Project State

The project is in a very early stage and breaking changes are likely to happen. We'd recommend to not yet use this in production or at least expect non-trivial effort required to upgrade to a new version.

For a more stable and robust alternative to MailWhale, check out postalsys/emailengine.

📦 Installation

Compile from source

# 1. Clone repo
$ git clone https://github.com/muety/mailwhale.git

# 2. Adapt config to your needs, i.e. set your SMTP server and credentials, etc.
$ cp config.default.yml config.yml
$ vi config.yml

# 3. Compile Web UI
$ cd webui/
$ yarn && yarn build
$ cd ..
# 4. Compile API
$ go build

# 5. Run it
$ ./mailwhale

From GitHub Release

# 1. Download latest release
curl -s https://api.github.com/repos/muety/mailwhale/releases/latest | jq -r ".assets[] | select(.name|match(\"Linux_$(arch).tar.gz\")) | .browser_download_url" | wget -qi -

# 2. Extract
mkdir mailwhale
tar xf mailwhale_*.tar.gz -C mailwhale
cd mailwhale

# 3.[Optional] Adapt config to your needs, i.e. set your SMTP server and credentials, etc.
# vi config.yml

# 4. Run it
./mailwhale

With Docker Image

$ docker run -d \
  -p 127.0.0.1:3000:3000 \
  -v "$(pwd)/config.yml":/app/config.yml:ro \
  -v mailwhale_data:/data \
  --name mailwhale \
  ghcr.io/muety/mailwhale

Build custom Docker Image

# 1. Clone repo
$ git clone https://github.com/muety/mailwhale.git

# 2. Adapt config to your needs, i.e. set your SMTP server and credentials, etc.
$ cp config.default.yml config.yml
$ vi config.yml

# 3. Build image
$ docker build -t mailwhale .

# 4. Create persistent volume
$ docker volume create mailwhale_data

# 5. Run
$ docker run -d \
  -p 127.0.0.1:3000:3000 \
  -v "$(pwd)/config.yml":/app/config.yml:ro \
  -v mailwhale_data:/data \
  --name mailwhale \
  mailwhale

Note: An official Docker image is about to come. Also, there will be no need to mount your config file into the container, as everything will be configurable using environment variables eventually.

Reverse Proxy

To run this app behind a reverse proxy, see here for example configurations for different web servers (works analogously for MailWhale). In addition, MW_WEB_PUBLIC_URL (or web.public_url, respectively) must be configured accordingly (set to the absolute URL of your MailWhale instance). Also see #43.

⌨️ Usage

First of all, you can get most tasks done through the web UI, available at http://localhost:3000.

1. Define a user

To get started with MailWhale, you need to create a user first. To do so, register a new user API or web UI. security.allow_signup needs to be set to true.

2. Create an API client

It is good practice to not authenticate against the API as a user directly. Instead, create an API client with limited privileges, that could easily be revoked in the future. A client is identified by a client ID and a client secret (or token), very similar to what you might already be familiar with from AWS APIs. Usually, such a client corresponds to an individual client application of yours, which wants to access MailWhale's API.

Request

$ curl -XPOST \
     -u 'admin@local.host:admin' \
     -H 'Content-Type: application/json' \
     --data-raw '{
         "description": "My juicy web app",
         "sender": "Epic Juice Store <noreply@epicjuicestore.org>",
         "permissions": ["send_mail"]
     }' \
     'http://localhost:3000/api/client'

Response

{
    "id": "SVNORFBUWGhxWGZSUUl0eA==",
    "description": "My juicy web app",
    "permissions": [
        "send_mail"
    ],
    "sender": "Epic Juice Store <noreply@epicjuicestore.org>",
    "api_key": "75c74447-c4af-453b-ad06-3a8ae969ed16"
}

The response contains your new client's ID (id) and secret (api_key). Remember these credentials, as they are needed for subsequent requests from your application.

Client authentication happens through HTTP basic auth. Most HTTP clients support basic auth out of the box (including cURL with its -u parameter). If your's doesn't, you can hash create the hash like so:

$ echo "Authorization: Basic $(echo '<client_id>:<client_secret>' | base64)"

# Result:
# Authorization: Basic U1ZOT1JGQlVXR2h4V0daU1VVbDBlQT09Ojc1Yzc0NDQ3LWM0YWYtNDUzYi1hZDA2LTNhOGFlOTY5ZWQxNg==

3. Send E-Mails

Plain text or HTML

$ curl -XPOST \
  -u '<client_id>:<client_secret>' \
  -H 'content-type: application/json' \
  --data '{
      "to": ["Jane Doe <jane@doe.com>"],
      "subject": "Dinner tonight?",
      "html": "<h1>Hey you!</h1><p>Wanna have dinner tonight?</p>"
  }' \
  'http://localhost:3000/api/mail'

You can also a text field instead, to send a plain text message.

Using a template

In case you have created a template using the web UI, you can reference it in a new mail like so:

$ curl -XPOST \
  -u '<client_id>:<client_secret>' \
  -H 'content-type: application/json' \
  --data '{
      "to": ["Jane Doe <jane@doe.com>"],
      "subject": "Dinner tonight?",
      "template_id": "8033ea08-2630-408b-82f9-d38b403243d0",
      "template_vars: {
        "text.greeting": "Hello new user!",
    }
  }' \
  'http://localhost:3000/api/mail'

🔧 Configuration Options

You can specify configuration options either via a config file (config.yml) or via environment variables. Here is an overview of all options.

| YAML Key | Environment Variable | Default | Description | |---------------------------|------------------------------|---------------------------|------------------------------------------------------------------------------------| | env | MW_ENV | dev | Whether to use development- or production settings | | mail.domain | MW_MAIL_DOMAIN | - | Default domain for sending mails | | web.listen_addr | MW_WEB_LISTEN_ADDR | 127.0.0.1:3000 | IP and port for the web server to listen on (can be IPv4 or IPv6) | | web.cors_origin | - | [http://localhost:5000] | List of URLs which to accept CORS requests for | | web.public_url | MW_PUBLIC_URL | http://localhost:3000 | The URL under which your MailWhale server is available from the public internet | | smtp.host | MW_SMTP_HOST | - | SMTP relay host name or IP | | smtp.port | MW_SMTP_PORT | - | SMTP relay port | | smtp.username | MW_SMTP_USER | - | SMTP relay authentication user name (leave blank to disable authentication) | | smtp.password | MW_SMTP_PASS | - | SMTP relay authentication password | | smtp.tls | MW_SMTP_TLS | false | Whether to require full TLS (not to be confused with STARTTLS) for the SMTP relay | | smtp.skip_verify_tls | MW_SMTP_SKIP_VERIFY_TLS | false | Whether to skip certificate verification (e.g. trust self-signed certs) | | store.path | MW_STORE_PATH | ./data.json.db | Target location of the database file

Related Skills

View on GitHub
GitHub Stars369
CategoryDevelopment
Updated18d ago
Forks36

Languages

Go

Security Score

100/100

Audited on Mar 9, 2026

No findings