• Stars
    star
    245
  • Rank 165,304 (Top 4 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 4 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

MailWhale

A bring-your-own-SMTP-server mail relay

πŸ“„ 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 \
  docker pull 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 '[email protected]:admin' \
     -H 'Content-Type: application/json' \
     --data-raw '{
         "description": "My juicy web app",
         "sender": "Epic Juice Store <[email protected]>",
         "permissions": ["send_mail"]
     }' \
     'http://localhost:3000/api/client'

Response

{
    "id": "SVNORFBUWGhxWGZSUUl0eA==",
    "description": "My juicy web app",
    "permissions": [
        "send_mail"
    ],
    "sender": "Epic Juice Store <[email protected]>",
    "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 <[email protected]>"],
      "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 <[email protected]>"],
      "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
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
security.pepper MW_SECURITY_PEPPER - Pepper to use for hashing user passwords
security.allow_signup MW_SECURITY_ALLOW_SIGNUP true Whether to allow the registration of new users
security.verify_users MW_SECURITY_VERIFY_USERS true Whether to require new users to activate their account using a confirmation mail
security.verify_senders MW_SECURITY_VERIFY_SENDERS true Whether to validate sender addresses and their domains' SPF records
security.block_list MW_SECURITY_BLOCK_LIST [] List of regexes used to block certain recipient addresses

Sender verification & SPF Check

By default, mails are sent using a randomly generated address in the From header, which belongs to the domain configured via mail.domain (i.e. [email protected]). Optionally, custom sender addresses can be configured on a per-API-client basis. However, it is recommended to properly configure SPF on that custom domain and instruct MailWhale to verify that configuration.

As a user, you need to configure your domain, which you want to use as part of your senders address (e.g. example.org for sending mails from User Server <[email protected]>), to publish an SPF record that delegates to the domain under which MailWhale is running (e.g. mailwhale.dev).

example.org.  IN  TXT v=spf1 include:mailwhale.dev

As a server operator of a MailWhale instance, you need to enable mail.verify_senders and set your mail.domain and web.public_url. For that domain, you need to configure an SPF record that allows your SMTP relay provider's (e.g. Mailbox.org, GMail, SendGrid, etc.) mail servers to be senders. Refer to your provider's documentation, e.g. this.

πŸš€ Features (planned)

Right now, this app is very basic. However, there are several cool features on our roadmap.

  • Bounce handling: Ultimately, we want to offer the ability to plug an IMAP server in addition, to get notified about bounced / undelivered mails.
  • Statistics: There will be basic statistics about when which client has sent how many mails, how many were successful or were bounced, etc.
  • Client libraries: To make the developer experience even smoother, client SDKs for different programming languages will we added some time.
  • Minor enhancements: IPv6- and TLS support, API documentation, ...

πŸ““ License

MIT

More Repositories

1

wakapi

πŸ“Š A minimalist, self-hosted WakaTime-compatible backend for coding statistics
Go
2,534
star
2

telepush

πŸ€– A simple bot to translate JSON HTTP requests into Telegram push messages
Go
449
star
3

mininote

πŸ“” A simple, self-hosted, encrypted Markdown note-taking editor
Vue
225
star
4

anchr

βš“οΈ Anchr provides you with a toolbox for tiny tasks on the internet, especially bookmark collections
JavaScript
181
star
5

website-watcher

πŸ•΅οΈβ€β™€οΈ Naively watch websites for changes on regular intervals.
Python
54
star
6

telegram-expense-bot

A bot that helps you manage and track your daily expenses.
JavaScript
48
star
7

anchr-android

πŸ“± Android client for Anchr.io link collections, built with Flutter
Dart
43
star
8

telegram-payment-bot

How to create a basic Telegram bot with Payments
JavaScript
42
star
9

telegram-bot-tutorial

How to create a basic Telegram bot
JavaScript
38
star
10

http-server-benchmarks

Some simple benchmarks of different HTTP servers in different languages
Java
27
star
11

http2-serverpush-proxy

A simple standalone reverse proxy that automatically enables server-push for assets related to a HTTP response.
JavaScript
26
star
12

gitcount

A command-line tool to estimate the time spent on a git project, based on a very simple heuristic
Go
25
star
13

safe-browse-url-lookup

A simplified NodeJS wrapper for Google's Safe Browsing API v4 to check whether a URL is malicious or not. See https://developers.google.com/safe-browsing/v4/ for more information.
JavaScript
19
star
14

kitsquid

πŸ™ Alternative course catalog for Karlsruhe Institute of Technology
Go
15
star
15

linkeddata-trivia

Auto-generated trivia questions based on DBPedia data.
JavaScript
15
star
16

hashcode-2018

Solution for Google Hash Code 2018 Qualification Round
Python
14
star
17

tello

Keyboard interface to control a DJI Tello drone with your PC
Go
13
star
18

talkycars-thesis

A Distributed Platform Approach to Cooperative Perception based on Celluar-V2X Communication
Python
10
star
19

telegram-paypalme-bot

A bot that help you easily request money from friends.
JavaScript
9
star
20

go-graphql-sse-example

Basic example application using Go + GraphQL Subscriptions + Server-Sent Events + MongoDB + VueJS
Go
8
star
21

caddy-remote-host

Caddy v2 plugin to match a request's client IP against a host name (similar to remote_ip)
Go
7
star
22

tg-chat-classification

Naive-Bayes based classification of Telegram chat messages.
Python
6
star
23

caddy-pirsch-plugin

A Caddy v2 plugin to track requests in Pirsch analytics
Go
5
star
24

popular-movies-android

Project 1 from Udacity Android Developer Nanodegree
Java
5
star
25

halite-bot-java

My rule-based solution for the Halite AI competition
Java
4
star
26

quiznerd-android

πŸ€“ A multiplayer coding quiz game for developers. Challenge your friends, compete in matches and test your skills in various programming languages.
Java
4
star
27

winscp2filezilla

A tool that migrates your saved servers from WinSCP to FileZilla.
Go
4
star
28

kit-lod16-knowledge-panel

Linked Open Data-based knowledge panel built during a seminar at Karlsruhe Institute of Technology
Java
4
star
29

broilerplate

A template project for new Go web backend applications
Go
3
star
30

readme-guestbook

A GitHub action to create a guestbook in your README from repository issues
JavaScript
3
star
31

express-request-limit

Express middleware to limit the request rate to specific routes, based on client IP address.
JavaScript
2
star
32

xyz-reader-android

Project 5 from Udacity Android Developer Nanodegree
Java
2
star
33

muetsch.io

My personal website and blog
Stylus
2
star
34

muety.github.io

HTML
1
star
35

baking-time-android

Project 3 from Udacity Android Developer Nanodegree
Java
1
star
36

hashcode-2021

Google HashCode 2021 Solutions
Java
1
star
37

telegram-bot-sdk

A JavaScript SDK to interact with the Telegram Bot API (https://core.telegram.org/bots/api) from your Node.js application.
JavaScript
1
star
38

operation-go

My solutions to the Operation Go hacking game by gocode.io
Go
1
star
39

srvctl

A mini tool to quickly perform certain actions on a server
PHP
1
star