├── .github └── workflows │ ├── master.yml │ └── release.yml ├── Dockerfile ├── LICENSE ├── README.md ├── build.yml ├── docker-compose.yml ├── entrypoint.sh └── set-exim4-update-conf /.github/workflows/master.yml: -------------------------------------------------------------------------------- 1 | name: 'master' 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - name: Docker Login 14 | run: docker login docker.pkg.github.com -u namshi -p $GITHUB_TOKEN 15 | env: 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | - name: Docker Build 18 | run: docker build --tag docker.pkg.github.com/namshi/docker-smtp/smtp:latest . 19 | - name: Docker Publish 20 | run: docker push docker.pkg.github.com/namshi/docker-smtp/smtp:latest 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'release' 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | - '!v*.*.*-*' 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Get the version 15 | id: get_version 16 | run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/} 17 | 18 | - name: Docker Login 19 | run: docker login docker.pkg.github.com -u namshi -p $GITHUB_TOKEN 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | - name: Docker Build 23 | run: docker build --tag docker.pkg.github.com/namshi/docker-smtp/smtp:${{ steps.get_version.outputs.VERSION }} . 24 | - name: Docker Publish 25 | run: docker push docker.pkg.github.com/namshi/docker-smtp/smtp:${{ steps.get_version.outputs.VERSION }} 26 | 27 | - name: Create Release 28 | id: create_release 29 | uses: actions/create-release@v1 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | with: 33 | tag_name: ${{ github.ref }} 34 | release_name: ${{ github.ref }} 35 | draft: false 36 | prerelease: false 37 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | MAINTAINER Oluwaseun Obajobi "oluwaseun.obajobi@namshi.com" 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y exim4-daemon-light && \ 7 | apt-get clean && \ 8 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ 9 | find /var/log -type f | while read f; do echo -ne '' > $f; done; 10 | 11 | COPY entrypoint.sh /bin/ 12 | COPY set-exim4-update-conf /bin/ 13 | 14 | RUN chmod a+x /bin/entrypoint.sh && \ 15 | chmod a+x /bin/set-exim4-update-conf 16 | 17 | EXPOSE 25 18 | ENTRYPOINT ["/bin/entrypoint.sh"] 19 | CMD ["exim", "-bd", "-q15m", "-v"] 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Namshi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker-SMTP 2 | [![](https://images.microbadger.com/badges/image/namshi/smtp.svg)](https://microbadger.com/images/namshi/smtp) 3 | 4 | This is a SMTP docker container for sending emails. You can also relay emails to gmail and amazon SES. 5 | 6 | ## Environment variables 7 | 8 | The container accepts `RELAY_NETWORKS` environment variable which *MUST* start with `:` e.g `:192.168.0.0/24` or `:192.168.0.0/24:10.0.0.0/16`. 9 | 10 | The container accepts `KEY_PATH` and `CERTIFICATE_PATH` environment variable that if provided will enable TLS support. The paths must be to the key and certificate file on a exposed volume. The keys will be copied into the container location. 11 | 12 | The container accepts `MAILNAME` environment variable which will set the outgoing mail hostname. 13 | 14 | The container also accepts the `PORT` environment variable, to set the port the mail daemon will listen on inside the container. The default port is `25`. 15 | 16 | To configure the binding address, you can use `BIND_IP` and `BIND_IP6` environment variables. The default `BIND_IP` is `0.0.0.0`. The default `BIND_IP6` is `::0`. 17 | 18 | To disable IPV6 you can set the `DISABLE_IPV6` environment variable to any value. 19 | 20 | The container accepts `OTHER_HOSTNAMES` environment variable which will set the list of domains for which this machine should consider itself the final destination. 21 | 22 | ## Below are scenarios for using this container 23 | 24 | ### As SMTP Server 25 | You don't need to specify any environment variable to get this up. 26 | 27 | ### As a Secondary SMTP Server 28 | Specify 'RELAY_DOMAINS' to setup what domains should be accepted to forward to lower distance MX server. 29 | 30 | Format is ` : : etc` 31 | 32 | ### As Gmail Relay 33 | You need to set the `GMAIL_USER` and `GMAIL_PASSWORD` to be able to use it. 34 | 35 | ### As Amazon SES Relay 36 | You need to set the `SES_USER` and `SES_PASSWORD` to be able to use it.
37 | You can override the SES region by setting `SES_REGION` as well. 38 | If you use Google Compute Engine you also should set `SES_PORT` to 2587. 39 | 40 | ### As generic SMTP Relay 41 | You can also use any generic SMTP server with authentication as smarthost.
42 | You need to set `SMARTHOST_ADDRESS`, `SMARTHOST_PORT` (connection parameters), `SMARTHOST_USER`, `SMARTHOST_PASSWORD` (authentication parameters), and `SMARTHOST_ALIASES`: this is a list of aliases to puth auth data for authentication, semicolon separated.
43 | 44 | ``` 45 | Example: 46 | 47 | * SMARTHOST_ADDRESS=mail.mysmtp.com 48 | * SMARTHOST_PORT=587 49 | * SMARTHOST_USER=myuser 50 | * SMARTHOST_PASSWORD=secret 51 | * SMARTHOST_ALIASES=*.mysmtp.com 52 | ``` 53 | -------------------------------------------------------------------------------- /build.yml: -------------------------------------------------------------------------------- 1 | exim: 2 | notify: 3 | - github 4 | - email-ses 5 | registry: namshi.net 6 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | smtp: 4 | image: namshi/smtp 5 | container_name: smtp_relay 6 | restart: always 7 | ports: 8 | - "25:25" 9 | environment: 10 | # # MUST start with : e.g RELAY_NETWORKS=:192.168.0.0/24:10.0.0.0/16 11 | # # if acting as a relay this or RELAY_DOMAINS must be filled out or incoming mail will be rejected 12 | # - RELAY_NETWORKS= :192.168.0.0/24 13 | # # what domains should be accepted to forward to lower distance MX server. 14 | # - RELAY_DOMAINS= : : 15 | # # To act as a Gmail relay 16 | # - GMAIL_USER= 17 | # - GMAIL_PASSWORD= 18 | # # For use with Amazon SES relay 19 | # - SES_USER= 20 | # - SES_PASSWORD= 21 | # - SES_REGION= 22 | # # if provided will enable TLS support 23 | # - KEY_PATH= 24 | # - CERTIFICATE_PATH= 25 | # # the outgoing mail hostname 26 | # - MAILNAME= 27 | # # set this to any value to disable ipv6 28 | # - DISABLE_IPV6= 29 | # # Generic SMTP Relay 30 | # - SMARTHOST_ADDRESS= 31 | # - SMARTHOST_PORT= 32 | # - SMARTHOST_USER= 33 | # - SMARTHOST_PASSWORD= 34 | # - SMARTHOST_ALIASES= 35 | 36 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Initialize localmacros as an empty file 5 | echo -n "" > /etc/exim4/exim4.conf.localmacros 6 | 7 | if [ "$MAILNAME" ]; then 8 | echo "MAIN_HARDCODE_PRIMARY_HOSTNAME = $MAILNAME" > /etc/exim4/exim4.conf.localmacros 9 | echo $MAILNAME > /etc/mailname 10 | fi 11 | 12 | if [ "$KEY_PATH" -a "$CERTIFICATE_PATH" ]; then 13 | if [ "$MAILNAME" ]; then 14 | echo "MAIN_TLS_ENABLE = yes" >> /etc/exim4/exim4.conf.localmacros 15 | else 16 | echo "MAIN_TLS_ENABLE = yes" >> /etc/exim4/exim4.conf.localmacros 17 | fi 18 | cp $KEY_PATH /etc/exim4/exim.key 19 | cp $CERTIFICATE_PATH /etc/exim4/exim.crt 20 | chgrp Debian-exim /etc/exim4/exim.key 21 | chgrp Debian-exim /etc/exim4/exim.crt 22 | chmod 640 /etc/exim4/exim.key 23 | chmod 640 /etc/exim4/exim.crt 24 | fi 25 | 26 | opts=( 27 | dc_local_interfaces "[${BIND_IP:-0.0.0.0}]:${PORT:-25} ; [${BIND_IP6:-::0}]:${PORT:-25}" 28 | dc_other_hostnames "${OTHER_HOSTNAMES}" 29 | dc_relay_nets "$(ip addr show dev eth0 | awk '$1 == "inet" { print $2 }' | xargs | sed 's/ /:/g')${RELAY_NETWORKS}" 30 | ) 31 | 32 | if [ "$DISABLE_IPV6" ]; then 33 | echo 'disable_ipv6=true' >> /etc/exim4/exim4.conf.localmacros 34 | fi 35 | 36 | if [ "$GMAIL_USER" -a "$GMAIL_PASSWORD" ]; then 37 | opts+=( 38 | dc_eximconfig_configtype 'smarthost' 39 | dc_smarthost 'smtp.gmail.com::587' 40 | dc_relay_domains "${RELAY_DOMAINS}" 41 | ) 42 | echo "*.gmail.com:$GMAIL_USER:$GMAIL_PASSWORD" > /etc/exim4/passwd.client 43 | elif [ "$SES_USER" -a "$SES_PASSWORD" ]; then 44 | opts+=( 45 | dc_eximconfig_configtype 'smarthost' 46 | dc_smarthost "email-smtp.${SES_REGION:=us-east-1}.amazonaws.com::${SES_PORT:=587}" 47 | dc_relay_domains "${RELAY_DOMAINS}" 48 | ) 49 | echo "*.amazonaws.com:$SES_USER:$SES_PASSWORD" > /etc/exim4/passwd.client 50 | # Allow to specify an arbitrary smarthost. 51 | # Parameters: SMARTHOST_USER, SMARTHOST_PASSWORD: authentication parameters 52 | # SMARTHOST_ALIASES: list of aliases to puth auth data for (semicolon separated) 53 | # SMARTHOST_ADDRESS, SMARTHOST_PORT: connection parameters. 54 | elif [ "$SMARTHOST_ADDRESS" ] ; then 55 | opts+=( 56 | dc_eximconfig_configtype 'smarthost' 57 | dc_smarthost "${SMARTHOST_ADDRESS}::${SMARTHOST_PORT-25}" 58 | dc_relay_domains "${RELAY_DOMAINS}" 59 | ) 60 | rm -f /etc/exim4/passwd.client 61 | if [ "$SMARTHOST_ALIASES" -a "$SMARTHOST_USER" -a "$SMARTHOST_PASSWORD" ] ; then 62 | echo "$SMARTHOST_ALIASES;" | while read -d ";" alias; do 63 | echo "${alias}:$SMARTHOST_USER:$SMARTHOST_PASSWORD" >> /etc/exim4/passwd.client 64 | done 65 | fi 66 | elif [ "$RELAY_DOMAINS" ]; then 67 | opts+=( 68 | dc_relay_domains "${RELAY_DOMAINS}" 69 | dc_eximconfig_configtype 'internet' 70 | ) 71 | else 72 | opts+=( 73 | dc_eximconfig_configtype 'internet' 74 | ) 75 | fi 76 | 77 | # allow to add additional macros by bind-mounting a file 78 | if [ -f /etc/exim4/_docker_additional_macros ]; then 79 | cat /etc/exim4/_docker_additional_macros >> /etc/exim4/exim4.conf.localmacros 80 | fi 81 | 82 | /bin/set-exim4-update-conf "${opts[@]}" 83 | 84 | exec "$@" 85 | -------------------------------------------------------------------------------- /set-exim4-update-conf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | conf='/etc/exim4/update-exim4.conf.conf' 5 | 6 | sedExpr='' 7 | while [ $# -gt 0 ]; do 8 | key="$1" 9 | value="$2" 10 | shift 2 11 | 12 | if ! grep -qE "^#?${key}=" "$conf"; then 13 | echo >&2 "error: '$key' not found in '$conf'" 14 | exit 1 15 | fi 16 | 17 | sed_escaped_value="$(echo "$value" | sed 's/[\/&]/\\&/g')" 18 | sedExpr+=$'\n\t'"s/^#?(${key})=.*/\1='${sed_escaped_value}'/;" 19 | done 20 | 21 | set -x 22 | sed -ri "$sedExpr"$'\n' "$conf" 23 | update-exim4.conf -v 24 | --------------------------------------------------------------------------------