update to multiarch

This commit is contained in:
2025-03-05 12:49:33 +01:00
parent 4c9dd48ef7
commit 349489c58b
7 changed files with 374 additions and 1 deletions

47
.drone.yml Normal file
View File

@@ -0,0 +1,47 @@
kind: pipeline
type: kubernetes
name: default
node_selector:
physical-node: dev2
trigger:
branch:
- master
event:
- push
workspace:
path: /drone/src
steps:
- name: build multiarch from dev
image: docker.io/owncloudci/drone-docker-buildx:4
privileged: true
settings:
cache-from: [ "registry.dev.format.hu/smtp" ]
registry: registry.dev.format.hu
repo: registry.dev.format.hu/smtp
tags: latest
dockerfile: Dockerfile
username:
from_secret: dev-hu-registry-username
password:
from_secret: dev-hu-registry-password
platforms:
- linux/amd64
- linux/arm64
- name: pull image to dockerhub
image: docker.io/owncloudci/drone-docker-buildx:4
privileged: true
settings:
cache-from: [ "safebox/smtp" ]
repo: safebox/smtp
tags: latest
username:
from_secret: dockerhub-username
password:
from_secret: dockerhub-password
platforms:
- linux/amd64
- linux/arm64

33
Dockerfile Normal file
View File

@@ -0,0 +1,33 @@
FROM alpine:3.20
ARG BUILD_DATE
LABEL \
maintainer="Logan Marchione <logan@loganmarchione.com>" \
org.opencontainers.image.authors="Logan Marchione <logan@loganmarchione.com>" \
org.opencontainers.image.title="docker-postfixrelay" \
org.opencontainers.image.description="Runs Postfix (as a relay) in Docker" \
org.opencontainers.image.created=$BUILD_DATE
RUN apk add --no-cache --update \
bash \
ca-certificates \
cyrus-sasl-login \
dumb-init \
postfix \
postfix-doc \
tzdata
EXPOSE 25
VOLUME [ "/var/spool/postfix" ]
COPY ./entrypoint.sh /
COPY VERSION /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/entrypoint.sh"]
HEALTHCHECK CMD netstat -ltn | grep -c ":25" || exit 1

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Logan Marchione
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

132
README.md
View File

@@ -1,2 +1,132 @@
# smtp-client
# docker-postfixrelay
[![CI/CD](https://github.com/loganmarchione/docker-postfixrelay/actions/workflows/main.yml/badge.svg)](https://github.com/loganmarchione/docker-postfixrelay/actions/workflows/main.yml)
[![Docker Image Size (latest semver)](https://img.shields.io/docker/image-size/loganmarchione/docker-postfixrelay)](https://hub.docker.com/r/loganmarchione/docker-postfixrelay)
Runs Postfix (as a relay) in Docker
- Source code: [GitHub](https://github.com/loganmarchione/docker-postfixrelay)
- Docker container: [Docker Hub](https://hub.docker.com/r/loganmarchione/docker-postfixrelay)
- Image base: [Alpine Linux](https://hub.docker.com/_/alpine/)
- Init system: [dumb-init](https://github.com/Yelp/dumb-init)
- Application: [Postfix](http://www.postfix.org/)
- Architecture: `linux/amd64,linux/arm64,linux/arm/v7`
## Explanation
- This runs Postfix (as a relay) in Docker.
- Most home ISPs block port 25, so outbound emails must be relayed through an external SMTP server (e.g., Gmail).
- This container acts as a single collections point for devices needing to send email.
- ⚠️ Postfix acts as an open relay. As such, this is not meant to be run on the internet, only on a trusted internal network! ⚠️
```
Internal (LAN) network Public internet
------------------
| |
| Device sending | | |
| email alert | ------------- | |
| | | | |
------------------ | | |
| | F |
------------------ v | i |
| | ------------------ | r | ----------------------------- -------------------
| Device sending | | | | e | | | | |
| email alert | ----> | This container | --| w |--> | SMTP server (e.g., Gmail) | ----> | Recipient email |
| | | | | a | | | | |
------------------ ------------------ | l | ----------------------------- -------------------
^ | l |
------------------ | | |
| | | | |
| Device sending | | | |
| email alert | ------------- | |
| |
------------------
```
## Requirements
- You must already have an account on an external SMTP server (e.g., Gmail, AWS SES, etc...).
- Your external SMTP server must be using encryption (i.e., plaintext is not allowed)
## Docker image information
### Docker image tags
- `latest`: Latest version
- `X.X.X`: [Semantic version](https://semver.org/) (use if you want to stick on a specific version)
### Environment variables
| Variable | Required? | Definition | Example | Comments |
|-------------|---------------------------|---------------------------------------------|----------------------------|--------------------------------------------------------------|
| TZ | Yes | Timezone | America/New_York | https://en.wikipedia.org/wiki/List_of_tz_database_time_zones |
| RELAY_HOST | Yes | Public SMTP server to use | smtp.gmail.com | |
| RELAY_PORT | Yes | Public SMTP port to use | 587 | |
| RELAY_USER | No | Address to login to $RELAY_HOST | SMTP username | |
| RELAY_PASS | No | Password to login to $RELAY_HOST | SMTP password | If using Gmail 2FA, you will need to setup an app password |
| TEST_EMAIL | No | Address to receive test email | receive_address@domain.com | If not set, test email will **not** be sent |
| MYORIGIN | No | Domain of the "from" address | domain.com | Needed for things like AWS SES where the domain must be set |
| FROMADDRESS | No | Changes the "from" address | my_email@domain.com | Needed for some SMTP services where the FROM address needs to be set, [fixes issue 19](https://github.com/loganmarchione/docker-postfixrelay/issues/19) |
| MYNETWORKS | No (default: 0.0.0.0/0) | Networks that Postfix will forward mail for | 1.2.3.4/24, 5.6.7.8/24 | Single or multiple trusted networks separated with a comma |
| MSG_SIZE | No (default: 10240000) | Postfix `message_size_limit` in bytes | 30720000 | |
| LOG_DISABLE | No (default: false) | Setting to `true` disables logging | true | |
### Ports
| Port on host | Port in container | Comments |
|---------------------------|-------------------|---------------------|
| Choose at your discretion | 25 | Postfix SMTP server |
### Volumes
| Volume on host | Volume in container | Comments |
|---------------------------|---------------------|------------------------------------|
| Choose at your discretion | /var/spool/postfix | Used to store Postfix's mail spool |
### Example usage
Below is an example docker-compose.yml file.
```
version: '3'
services:
postfixrelay:
container_name: docker-postfixrelay
restart: unless-stopped
environment:
- TZ=America/New_York
- RELAY_HOST=smtp.gmail.com
- RELAY_PORT=587
- RELAY_USER=your_email_here@gmail.com
- RELAY_PASS=your_password_here
- TEST_EMAIL=test_email@domain.com
- MYORIGIN=domain.com
- FROMADDRESS=my_email@domain.com
- MYNETWORKS=1.2.3.4/24
- MSG_SIZE=30720000
- LOG_DISABLE=true
networks:
- postfixrelay
ports:
- '25:25'
volumes:
- 'postfixrelay_data:/var/spool/postfix'
image: loganmarchione/docker-postfixrelay:latest
networks:
postfixrelay:
volumes:
postfixrelay_data:
driver: local
```
Below is an example of running locally (used to edit/test/debug).
```
# Build the Dockerfile
docker compose -f docker-compose-dev.yml up -d
# View logs
docker compose -f docker-compose-dev.yml logs -f
# Destroy when done
docker compose -f docker-compose-dev.yml down
```
## TODO
- [x] ~~Add a [healthcheck](https://docs.docker.com/engine/reference/builder/#healthcheck)~~
- [ ] Add TLS support for SMTPD and listen on 587

1
VERSION Normal file
View File

@@ -0,0 +1 @@
1.4.6

33
docker-compose-dev.yml Normal file
View File

@@ -0,0 +1,33 @@
version: '3'
services:
postfixrelay:
container_name: docker-postfixrelay
restart: unless-stopped
build:
context: .
dockerfile: Dockerfile
environment:
- TZ=America/New_York
- RELAY_HOST=smtp.gmail.com
- RELAY_PORT=587
- RELAY_USER=your_email_here@gmail.com
- RELAY_PASS=your_password_here
- TEST_EMAIL=test_email@domain.com
- MYORIGIN=domain.com
- FROMADDRESS=my_email@domain.com
- MYNETWORKS=1.2.3.4/24
- MSG_SIZE=30720000
- LOG_DISABLE=true
networks:
- postfixrelay
ports:
- '25:25'
volumes:
- 'postfixrelay_data:/var/spool/postfix'
networks:
postfixrelay:
volumes:
postfixrelay_data:
driver: local

108
entrypoint.sh Normal file
View File

@@ -0,0 +1,108 @@
#!/bin/sh -e
printf "#####\n"
printf "# Container starting up!\n"
printf "#####\n"
# Test variables for timezone
if [ -z "$TZ" ]; then
printf "# ERROR: TZ is undefined, exiting!\n"
else
printf "# STATE: Setting container timezone to $TZ\n"
ln -sf /usr/share/zoneinfo/"$TZ" /etc/localtime
echo "$TZ" > /etc/timezone
fi
# Test variables for relay
if [[ -z "$RELAY_HOST" || -z "$RELAY_PORT" ]]; then
printf "# ERROR: Either RELAY_HOST or RELAY_PORT are undefined, exiting!\n"
exit 1
fi
# Create directories
printf "# STATE: Changing permissions\n"
postfix set-permissions
# Set logging
if [[ "$LOG_DISABLE" == "true" ]]; then
printf "# WARN: Setting Postfix logging to /dev/null\n"
else
printf "# STATE: Setting Postfix logging to /dev/stdout\n"
postconf -e "maillog_file = /dev/stdout"
fi
# Configure Postfix
printf "# STATE: Configuring Postfix\n"
postconf -e "inet_interfaces = all"
postconf -e "mydestination ="
postconf -e "mynetworks = ${MYNETWORKS:=0.0.0.0/0}"
postconf -e "relayhost = [$RELAY_HOST]:$RELAY_PORT"
# Set the "from" domain, needed for things like AWS SES
if [[ -z "$MYORIGIN" ]]; then
printf "# WARN: MYORIGIN is undefined, continuing\n"
else
printf "# STATE: MYORIGIN is defined as $MYORIGIN\n"
postconf -e "myorigin = $MYORIGIN"
fi
# Set the "from" address, needed for some SMTP providers
# https://serverfault.com/questions/147921/forcing-the-from-address-when-postfix-relays-over-smtp
if [[ -z "$FROMADDRESS" ]]; then
printf "# WARN: FROMADDRESS is undefined, continuing\n"
else
printf "# STATE: FROMADDRESS is defined as $FROMADDRESS\n"
postconf -e "smtp_header_checks = regexp:/etc/postfix/header_checks"
echo "/^From:.*/ REPLACE From: $FROMADDRESS" | tee /etc/postfix/header_checks > /dev/null
postconf -e "sender_canonical_maps = regexp:/etc/postfix/sender_canonical_maps"
echo "/.+/ $FROMADDRESS" | tee /etc/postfix/sender_canonical_maps > /dev/null
fi
# Set the message_size_limit
if [[ -z "$MSG_SIZE" ]]; then
printf "# WARN: MSG_SIZE is undefined, continuing\n"
else
printf "# STATE: MSG_SIZE is defined as $MSG_SIZE\n"
postconf -e "message_size_limit = $MSG_SIZE"
fi
# Client settings (for sending to the relay)
postconf -e "smtp_tls_security_level = encrypt"
postconf -e "smtp_tls_loglevel = 1"
postconf -e "smtp_tls_note_starttls_offer = yes"
postconf -e "smtp_sasl_auth_enable = yes"
postconf -e "smtp_sasl_security_options = noanonymous"
postconf -e "smtp_sasl_password_maps = lmdb:/etc/postfix/sasl_passwd"
postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
# Create password file
# Alpine 3.13 dropped support for Berkeley DB, so using lmdb instead
# https://wiki.alpinelinux.org/wiki/Release_Notes_for_Alpine_3.13.0#Deprecation_of_Berkeley_DB_.28BDB.29
echo "[$RELAY_HOST]:$RELAY_PORT $RELAY_USER:$RELAY_PASS" > /etc/postfix/sasl_passwd
chown root:root /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd
postmap lmdb:/etc/postfix/sasl_passwd
rm -f /etc/postfix/sasl_passwd
chown root:root /etc/postfix/sasl_passwd.lmdb
chmod 600 /etc/postfix/sasl_passwd.lmdb
# Rebuild the database for the mail aliases file
newaliases
# Send test email
# Test for variable and queue the message now, it will send when Postfix starts
if [[ -z "$TEST_EMAIL" ]]; then
printf "# WARN: TEST_EMAIL is undefined, continuing without a test email\n"
else
printf "# STATE: Sending test email\n"
echo -e "Subject: Postfix relay test \r\nTest of Postfix relay from Docker container startup\nSent on $(date)\n" | sendmail -F "[Alert from Postfix]" "$TEST_EMAIL"
fi
# Start Postfix
# Nothing else can log after this
printf "# STATE: Starting Postfix\n"
if [[ "$LOG_DISABLE" == "true" ]]; then
postfix start-fg > /dev/null
else
postfix start-fg
fi