An Alpine Linux-based Postfix SMTP relay designed for containers. It supports runtime configuration via environment variables, optional SASL authentication to an upstream relay host, and logs to stdout for docker logs and CloudWatch (ECS).
- Alpine-based, minimal footprint
- Postfix runs in foreground (
postfix start-fg), logs to stdout - Configure Postfix at runtime with environment variables:
- Any
POSTFIX_*orpostfix_*variable is applied viapostconf - Supports both lower- and UPPER-CASE variants (e.g.,
POSTFIX_relayhostandPOSTFIX_RELAYHOST)
- Any
- Optional SASL authentication when
SMTP_USERNAMEandSMTP_PASSWORDare set
Pull and run the pre-built image from Docker Hub:
docker pull croneu/postfix-relayer:latestBasic example (relay through AWS SES):
docker run -d --name postfix-relay \
-p 25:25 \
-e POSTFIX_myhostname=relay.example.com \
-e POSTFIX_myorigin=example.com \
-e POSTFIX_relayhost='[email-smtp.us-east-1.amazonaws.com]:587' \
-e SMTP_USERNAME='your-ses-username' \
-e SMTP_PASSWORD='your-ses-password' \
croneu/postfix-relayer:latestCheck logs:
docker logs -f postfix-relaySee docker-compose.yml in this repo for a ready-to-use example.
Resources:
PostfixTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: postfix-relay
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: 256
Memory: 512
ExecutionRoleArn: !GetAtt ECSExecutionRole.Arn
ContainerDefinitions:
- Name: postfix-relay
Image: croneu/postfix-relayer:latest
Essential: true
PortMappings:
- ContainerPort: 25
Protocol: tcp
Environment:
- Name: POSTFIX_myhostname
Value: relay.example.com
- Name: POSTFIX_myorigin
Value: example.com
- Name: POSTFIX_relayhost
Value: '[email-smtp.us-east-1.amazonaws.com]:587'
Secrets:
- Name: SMTP_USERNAME
ValueFrom: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:postfix/smtp-username'
- Name: SMTP_PASSWORD
ValueFrom: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:postfix/smtp-password'
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: /ecs/postfix-relay
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: postfix- Any environment variable beginning with
POSTFIX_orpostfix_is converted to lowercase and applied usingpostconf -e "key=value". - Example:
POSTFIX_mydestination=localhost→postconf -e "mydestination=localhost"POSTFIX_RELAYHOST=[smtp.example.com]:587→postconf -e "relayhost=[smtp.example.com]:587"
To enable SASL authentication, set the following environment variables:
SMTP_USERNAMESMTP_PASSWORD
- AWS SES:
POSTFIX_relayhost=[email-smtp.<region>.amazonaws.com]:587 SMTP_USERNAME=<ses_smtp_user> SMTP_PASSWORD=<ses_smtp_password> # Cater to the SES rate limit: ~14 msgs/s POSTFIX_smtp_destination_concurrency_limit=14 POSTFIX_smtp_destination_rate_delay=1s POSTFIX_smtp_extra_recipient_limit=10
- Generic provider (port 587 with STARTTLS):
POSTFIX_relayhost=[smtp.example.com]:587 [email protected] SMTP_PASSWORD=******
The image is build and pushed automatically to Docker Hub via GitHub Actions.
Using the Makefile:
make buildOr using Docker directly:
docker build -t croneu/postfix-relayer:latest .Note: The Dockerfile uses Alpine Linux 3.22 (pinned version) for reproducible builds.
The project includes a Makefile with comprehensive tests:
# Run all tests
make test
# Run individual tests
make test-basic # Test basic configuration
make test-uppercase # Test UPPERCASE env variables
make test-sasl # Test SASL authentication
# Other useful commands
make help # Show all available targets
make clean # Clean up test containersNote: Ensure POSTFIX_relayhost (or POSTFIX_RELAYHOST) is set when using SASL (e.g., [smtp.example.com]:587).
MIT (or your preferred OSS license)