Adding the configuration change for multiple provider, Making the service run in foreground and adding test
This commit is contained in:
1 parent
85ab503afb
commit
4eaa4d91ea
10 files changed
+1613
-114
No files matched your search
@@ -1,9 +1,8 @@
|
|||||||
name: Build and Push Docker Image
|
name: Build and Push Docker Image
|
||||||
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 1 * *' # This runs at midnight on the first day of every month
|
- cron: "0 0 1 * *" # This runs at midnight on the first day of every month
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@@ -30,4 +29,3 @@ jobs:
|
|||||||
|
|
||||||
- name: Push the Docker image
|
- name: Push the Docker image
|
||||||
run: docker push ${{ env.IMAGE_NAME }}
|
run: docker push ${{ env.IMAGE_NAME }}
|
||||||
|
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
# Environment files with credentials
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Data directories
|
||||||
|
data/
|
||||||
|
logs/
|
||||||
|
mail/
|
||||||
|
spool/
|
||||||
|
|
||||||
|
# Docker volumes
|
||||||
|
/var/log/
|
||||||
|
/var/mail/
|
||||||
|
/var/spool/
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
*.old
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
# Postfix specific
|
||||||
|
sasl_passwd
|
||||||
|
sasl_passwd.db
|
||||||
|
header_tag
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
*.log
|
||||||
+36
-45
@@ -1,67 +1,58 @@
|
|||||||
#Postfix relay
|
FROM docker.io/library/alpine:3.19
|
||||||
FROM docker.io/library/alpine:latest
|
|
||||||
|
|
||||||
# Variables for Labels:
|
# Variables for Labels
|
||||||
ARG VENDOR="k2patel"
|
ARG VENDOR="your-org"
|
||||||
ARG COMPONENT="postfix-relay"
|
ARG COMPONENT="postfix-relay"
|
||||||
ARG BUILD_DATE
|
ARG BUILD_DATE
|
||||||
ARG GIT_REPO
|
ARG GIT_REPO="https://github.com/your-org/docker-postfix"
|
||||||
ARG VCS_REF
|
ARG VCS_REF
|
||||||
ARG VERSION="1"
|
ARG VERSION="2.0"
|
||||||
ARG NAME="dockerized-${COMPONENT}"
|
ARG NAME="dockerized-${COMPONENT}"
|
||||||
ARG DESCRIPTION="dockerized environment."
|
ARG DESCRIPTION="Postfix SMTP relay supporting multiple providers (Maileroo, Mailtrap, SendGrid)"
|
||||||
ARG DOCUMENTATION="https://git.k2patel.in"
|
ARG DOCUMENTATION="https://github.com/your-org/docker-postfix"
|
||||||
ARG AUTHOR="k2patel<k2patel@live.com>"
|
ARG AUTHOR="Your Name <your-email@example.com>"
|
||||||
ARG LICENSE="MIT"
|
ARG LICENSE="MIT"
|
||||||
# END Variables
|
|
||||||
|
|
||||||
#########################################
|
# Labels
|
||||||
LABEL org.label-schema.build-date="${BUILD_DATE}" \
|
LABEL org.label-schema.build-date="${BUILD_DATE}" \
|
||||||
org.label-schema.name="${NAME}" \
|
org.label-schema.name="${NAME}" \
|
||||||
org.label-schema.description="${DESCRIPTION}" \
|
org.label-schema.description="${DESCRIPTION}" \
|
||||||
org.label-schema.vcs-ref="${VCS_REF}" \
|
org.label-schema.vcs-ref="${VCS_REF}" \
|
||||||
org.label-schema.vcs-url="${GIT_REPO}" \
|
org.label-schema.vcs-url="${GIT_REPO}" \
|
||||||
org.label-schema.url="${GIT_REPO}" \
|
|
||||||
org.label-schema.vendor="${VENDOR}" \
|
org.label-schema.vendor="${VENDOR}" \
|
||||||
org.label-schema.version="${VERSION}" \
|
org.label-schema.version="${VERSION}"
|
||||||
org.label-schema.usage="${DOCUMENTATION}"
|
|
||||||
|
|
||||||
LABEL org.opencontainers.image.created="${BUILD_DATE}" \
|
# Install required packages
|
||||||
org.opencontainers.image.url="${GIT_REPO}" \
|
RUN apk add --no-cache \
|
||||||
org.opencontainers.image.source="${GIT_REPO}" \
|
postfix \
|
||||||
org.opencontainers.image.version="${VERSION}" \
|
postfix-pcre \
|
||||||
org.opencontainers.image.revision="${VCS_REF}" \
|
cyrus-sasl \
|
||||||
org.opencontainers.image.vendor="${VENDOR}" \
|
cyrus-sasl-login \
|
||||||
org.opencontainers.image.title="${NAME}" \
|
libsasl \
|
||||||
org.opencontainers.image.description="${DESCRIPTION}" \
|
ca-certificates \
|
||||||
org.opencontainers.image.documentation="${DOCUMENTATION}" \
|
bash \
|
||||||
org.opencontainers.image.authors="${AUTHOR}" \
|
tzdata \
|
||||||
org.opencontainers.image.licenses="${LICENSE}"
|
mailx
|
||||||
#########################################
|
|
||||||
|
|
||||||
ENV TIMEZONE=${TIMEZONE}
|
# Create necessary directories
|
||||||
ENV SMTP_SERVER=${SMTP_SERVER}
|
RUN mkdir -p /var/spool/postfix /etc/postfix/sasl
|
||||||
ENV SERVER_HOSTNAME=${SERVER_HOSTNAME}
|
|
||||||
ENV SMTP_PORT=${SMTP_PORT}
|
|
||||||
ENV DOMAIN=${DOMAIN}
|
|
||||||
ENV SMTP_USERNAME=${SMTP_USERNAME}
|
|
||||||
ENV SMTP_PASSWORD=${SMTP_PASSWORD}
|
|
||||||
|
|
||||||
# Intall Needed Package
|
# Copy entrypoint script
|
||||||
RUN apk add --no-cache postfix libsasl supervisor ca-certificates bash rsyslog cyrus-sasl
|
COPY run.sh /run.sh
|
||||||
|
|
||||||
#Configure nodaemon mode for supervisord
|
|
||||||
RUN sed -i -e "s/^nodaemon=false/nodaemon=true/" /etc/supervisord.conf
|
|
||||||
#Change postfix to listen on all the interface
|
|
||||||
RUN sed -i -e 's/inet_interfaces = localhost/inet_interfaces = all/g' /etc/postfix/main.cf
|
|
||||||
|
|
||||||
COPY etc/ /etc/
|
|
||||||
VOLUME ["/var/log", "/var/mail", "/var/spool/postfix"]
|
|
||||||
COPY run.sh /
|
|
||||||
RUN chmod +x /run.sh
|
RUN chmod +x /run.sh
|
||||||
|
|
||||||
|
# Initialize postfix
|
||||||
RUN newaliases
|
RUN newaliases
|
||||||
|
|
||||||
|
# Expose SMTP port
|
||||||
EXPOSE 25
|
EXPOSE 25
|
||||||
|
|
||||||
ENTRYPOINT /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
# Volumes for persistence
|
||||||
|
VOLUME ["/var/spool/postfix"]
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \
|
||||||
|
CMD postfix status || exit 1
|
||||||
|
|
||||||
|
# Run postfix in foreground
|
||||||
|
ENTRYPOINT ["/run.sh"]
|
||||||
@@ -1,2 +1,462 @@
|
|||||||
# docker-postfix
|
# Docker Postfix SMTP Relay
|
||||||
Postfix relay for personal use
|
|
||||||
|
A lightweight Postfix SMTP relay container supporting multiple email service providers including Maileroo, Mailtrap, SendGrid, and any generic SMTP server.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🚀 Multi-provider support (Maileroo, Mailtrap, SendGrid, Gmail, Office365, any SMTP)
|
||||||
|
- 🔒 TLS/SSL encryption
|
||||||
|
- 🌐 Auto-detects /16 subnet for relay
|
||||||
|
- 📝 All logs to stderr (`docker logs`)
|
||||||
|
- 🏥 Built-in health checks
|
||||||
|
- 🔧 Simple Makefile-based operations
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Clone and Configure
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/your-org/docker-postfix.git
|
||||||
|
cd docker-postfix
|
||||||
|
cp env.sample .env
|
||||||
|
nano .env # Edit with your SMTP provider details
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Build and Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make build
|
||||||
|
make up
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make test TO=your@email.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Required | Default | Description |
|
||||||
|
|----------|----------|---------|-------------|
|
||||||
|
| `SMTP_SERVER` | Yes | - | SMTP server hostname |
|
||||||
|
| `SMTP_PORT` | Yes | 587 | SMTP server port |
|
||||||
|
| `SMTP_USERNAME` | Yes | - | SMTP username |
|
||||||
|
| `SMTP_PASSWORD` | Yes | - | SMTP password |
|
||||||
|
| `DOMAIN` | Yes | - | Domain for outgoing mail |
|
||||||
|
| `SERVER_HOSTNAME` | No | Auto | Server FQDN |
|
||||||
|
| `TIMEZONE` | No | America/New_York | Timezone |
|
||||||
|
| `SMTP_NETWORKS` | No | Auto /16 | Additional networks (comma-separated CIDR) |
|
||||||
|
| `SMTP_LISTEN_PORT` | No | 25 | Port to expose on host |
|
||||||
|
| `LOCAL_NETWORK` | No | Auto-detected | Override local network CIDR (e.g., 192.168.0.0/16) |
|
||||||
|
| `DEBUG` | No | no | Enable debug logging |
|
||||||
|
|
||||||
|
### Provider Examples
|
||||||
|
|
||||||
|
#### Maileroo
|
||||||
|
```bash
|
||||||
|
SMTP_SERVER=smtp.maileroo.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=noreply@example.com
|
||||||
|
SMTP_PASSWORD=your_password
|
||||||
|
DOMAIN=example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Mailtrap
|
||||||
|
```bash
|
||||||
|
SMTP_SERVER=live.smtp.mailtrap.io
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=your_username
|
||||||
|
SMTP_PASSWORD=your_password
|
||||||
|
DOMAIN=example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SendGrid
|
||||||
|
```bash
|
||||||
|
SMTP_SERVER=smtp.sendgrid.net
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=apikey
|
||||||
|
SMTP_PASSWORD=your_api_key
|
||||||
|
DOMAIN=example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: For SendGrid, username must be `apikey` (literal string).
|
||||||
|
|
||||||
|
#### Gmail
|
||||||
|
```bash
|
||||||
|
SMTP_SERVER=smtp.gmail.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=your_email@gmail.com
|
||||||
|
SMTP_PASSWORD=your_app_password
|
||||||
|
DOMAIN=gmail.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Makefile Commands
|
||||||
|
|
||||||
|
All operations are handled through the Makefile in the `test/` directory.
|
||||||
|
|
||||||
|
### Setup Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
|
||||||
|
make build # Build the Docker image
|
||||||
|
make up # Start the container
|
||||||
|
make down # Stop the container
|
||||||
|
make restart # Restart the container
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitoring Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make logs # View logs (follow mode)
|
||||||
|
make logs-tail # View last 100 lines
|
||||||
|
make status # Show container and Postfix status
|
||||||
|
make queue # View mail queue
|
||||||
|
make health # Check container health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Maintenance Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make shell # Open shell in container
|
||||||
|
make config # Show Postfix configuration
|
||||||
|
make test # Send test email (auto-detects container)
|
||||||
|
make flush # Flush mail queue
|
||||||
|
make check # Validate Postfix configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cleanup Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make clean # Remove container and volumes
|
||||||
|
make clean-all # Remove everything including images
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make debug # Start with debug mode enabled
|
||||||
|
make validate # Validate .env file
|
||||||
|
make queue-delete # Delete all messages in queue
|
||||||
|
make stats # Show real-time container stats
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Command List
|
||||||
|
|
||||||
|
Run `make help` or just `make` to see all available commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network Configuration
|
||||||
|
|
||||||
|
The container automatically allows relay from:
|
||||||
|
- Localhost (127.0.0.0/8)
|
||||||
|
- Auto-detected /16 subnet
|
||||||
|
|
||||||
|
To add custom networks:
|
||||||
|
```bash
|
||||||
|
SMTP_NETWORKS=192.168.1.0/24,10.0.0.0/8
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using with Applications
|
||||||
|
|
||||||
|
Configure your application to use the relay:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
your-app:
|
||||||
|
environment:
|
||||||
|
MAIL_HOST: postfix-relay
|
||||||
|
MAIL_PORT: 25
|
||||||
|
depends_on:
|
||||||
|
- postfix
|
||||||
|
```
|
||||||
|
|
||||||
|
Connection details:
|
||||||
|
- **Host**: `postfix-relay`
|
||||||
|
- **Port**: `25`
|
||||||
|
- **Authentication**: Not required for local network
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Quick Test (Recommended)
|
||||||
|
|
||||||
|
The easiest way to test your Postfix relay:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make test TO=recipient@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**That's it!** No configuration needed.
|
||||||
|
|
||||||
|
### What Gets Auto-Detected?
|
||||||
|
|
||||||
|
The test script automatically finds and configures:
|
||||||
|
|
||||||
|
| Feature | What Happens | Override Option |
|
||||||
|
|---------|--------------|-----------------|
|
||||||
|
| **Container Name** | Finds containers using `docker-postfix-postfix` image | Specify as first arg |
|
||||||
|
| **FROM Address** | Uses `noreply@DOMAIN` from container env | `FROM=email@domain.com` |
|
||||||
|
| **SMTP Port** | Detects mapped port (e.g., `25` or custom) | N/A (always detected) |
|
||||||
|
| **Host IP** | Converts `0.0.0.0` → `127.0.0.1` for local testing | N/A (always detected) |
|
||||||
|
| **Subject** | Defaults to "Test Email from Postfix Relay" | `SUBJECT="Your Subject"` |
|
||||||
|
|
||||||
|
**No manual configuration required** - just provide the recipient email!
|
||||||
|
|
||||||
|
### Advanced Testing Options
|
||||||
|
|
||||||
|
**With custom FROM address:**
|
||||||
|
```bash
|
||||||
|
make test TO=user@example.com FROM=noreply@mydomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**With custom subject:**
|
||||||
|
```bash
|
||||||
|
make test TO=user@example.com FROM=sender@domain.com SUBJECT="My Test Email"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Using the test script directly:**
|
||||||
|
```bash
|
||||||
|
./test-email.sh user@example.com
|
||||||
|
./test-email.sh user@example.com sender@mydomain.com
|
||||||
|
./test-email.sh user@example.com sender@mydomain.com "Custom Subject"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manual container specification (if auto-detection fails):**
|
||||||
|
```bash
|
||||||
|
./test-email.sh my-container user@example.com sender@domain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Script Features
|
||||||
|
|
||||||
|
The `test-email.sh` script automatically:
|
||||||
|
- Finds containers using `docker-postfix-postfix` image
|
||||||
|
- Detects port mapping and converts `0.0.0.0` to `127.0.0.1`
|
||||||
|
- Uses proper SMTP protocol via sendmail
|
||||||
|
- Falls back to mail command if needed
|
||||||
|
- Shows queue status after sending
|
||||||
|
- Provides colored output for easy reading
|
||||||
|
|
||||||
|
### Validation Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make check # Validate Postfix configuration
|
||||||
|
make validate # Validate .env file
|
||||||
|
make queue # View mail queue
|
||||||
|
make config # Show current Postfix config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Email Not Received
|
||||||
|
|
||||||
|
**1. Check container logs:**
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make logs-tail # Last 100 lines
|
||||||
|
make logs # Follow in real-time
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Check mail queue:**
|
||||||
|
```bash
|
||||||
|
make queue # View queued messages
|
||||||
|
make flush # Force processing
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Verify configuration:**
|
||||||
|
```bash
|
||||||
|
make config # Show Postfix config
|
||||||
|
make check # Validate config
|
||||||
|
make validate # Validate .env file
|
||||||
|
```
|
||||||
|
|
||||||
|
### SMTP Protocol Errors
|
||||||
|
|
||||||
|
If you see "improper command pipelining" errors:
|
||||||
|
|
||||||
|
**Use the test script** (handles protocol correctly):
|
||||||
|
```bash
|
||||||
|
./test-email.sh user@example.com sender@domain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify FROM domain matches DOMAIN setting:**
|
||||||
|
```bash
|
||||||
|
# In .env file
|
||||||
|
DOMAIN=mydomain.com
|
||||||
|
|
||||||
|
# Use matching FROM address
|
||||||
|
make test TO=user@example.com FROM=noreply@mydomain.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**Check mynetworks configuration:**
|
||||||
|
```bash
|
||||||
|
docker exec postfix-relay postconf mynetworks
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container Not Auto-Detected
|
||||||
|
|
||||||
|
**1. Verify container is running:**
|
||||||
|
```bash
|
||||||
|
docker ps | grep postfix
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Start the container:**
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make up
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Manually specify container:**
|
||||||
|
```bash
|
||||||
|
./test-email.sh my-container-name user@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable Debug Mode
|
||||||
|
|
||||||
|
For detailed SMTP transaction logs:
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make debug
|
||||||
|
```
|
||||||
|
|
||||||
|
### Emails Stuck in Queue
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make queue # View queue
|
||||||
|
make flush # Force processing
|
||||||
|
make queue-delete # Delete all (with confirmation)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Network Configuration Issues
|
||||||
|
|
||||||
|
**Override auto-detected network:**
|
||||||
|
```bash
|
||||||
|
# In .env file
|
||||||
|
LOCAL_NETWORK=192.168.1.0/24
|
||||||
|
```
|
||||||
|
|
||||||
|
**Add additional networks:**
|
||||||
|
```bash
|
||||||
|
SMTP_NETWORKS=10.0.0.0/8,172.16.0.0/12
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container Health Issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make status # Check status
|
||||||
|
make health # Check health status
|
||||||
|
make restart # Restart container
|
||||||
|
make down # Stop container
|
||||||
|
make up # Start fresh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Testing Examples
|
||||||
|
|
||||||
|
**Simple test with Gmail:**
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
make test TO=youraddress@gmail.com
|
||||||
|
# FROM will auto-detect from DOMAIN in .env
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test with custom FROM and subject:**
|
||||||
|
```bash
|
||||||
|
make test TO=client@example.com FROM=support@mycompany.com SUBJECT="Production Test"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test from command line:**
|
||||||
|
```bash
|
||||||
|
./test-email.sh user@example.com noreply@mydomain.com "Hello World"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify email was sent:**
|
||||||
|
```bash
|
||||||
|
make queue # Should show empty queue if sent
|
||||||
|
make logs-tail # Check for "status=sent"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Initial setup
|
||||||
|
cd docker-postfix
|
||||||
|
cp env.sample .env
|
||||||
|
nano .env
|
||||||
|
|
||||||
|
# Build and start
|
||||||
|
cd test
|
||||||
|
make build
|
||||||
|
make up
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
make status
|
||||||
|
make logs
|
||||||
|
|
||||||
|
# Test email delivery
|
||||||
|
make test TO=your@email.com
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
make down
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
|
||||||
|
# Start with debug
|
||||||
|
make debug
|
||||||
|
|
||||||
|
# Check logs in another terminal
|
||||||
|
make logs
|
||||||
|
|
||||||
|
# Restart after changes
|
||||||
|
make restart
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitoring Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
|
||||||
|
# Check everything
|
||||||
|
make status
|
||||||
|
make health
|
||||||
|
make queue
|
||||||
|
make logs-tail
|
||||||
|
|
||||||
|
# Continuous monitoring
|
||||||
|
make logs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
- Store credentials in `.env` (never commit to git)
|
||||||
|
- Limit relay to trusted networks only
|
||||||
|
- TLS automatically enabled for known providers
|
||||||
|
- Use app-specific passwords for Gmail
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - See [LICENSE](LICENSE) file for details.
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues and questions, please open an issue on GitHub.
|
||||||
+45
-16
@@ -1,19 +1,48 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postfix:
|
postfix:
|
||||||
container_name: postfix
|
build: .
|
||||||
image: docker.io/k2patel/postfix:latest
|
container_name: postfix-relay
|
||||||
ports:
|
hostname: ${SERVER_HOSTNAME:-postfix-relay}
|
||||||
- "10825:25/tcp"
|
|
||||||
environment:
|
|
||||||
TIMEZONE: ${TIMEZONE}
|
|
||||||
SMTP_SERVER: ${SMTP_SERVER}
|
|
||||||
SERVER_HOSTNAME: ${SERVER_HOSTNAME}
|
|
||||||
SMTP_PORT: ${SMTP_PORT}
|
|
||||||
DOMAIN: ${DOMAIN}
|
|
||||||
SMTP_USERNAME: ${SMTP_USERNAME}
|
|
||||||
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
|
||||||
volumes:
|
|
||||||
- "${DATA_FOLDER}/logs:/var/log"
|
|
||||||
- "${DATA_FOLDER}/mail:/var/mail"
|
|
||||||
- "${DATA_FOLDER}/spool:/var/spool/postfix"
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${SMTP_LISTEN_PORT:-25}:25"
|
||||||
|
environment:
|
||||||
|
- TIMEZONE=${TIMEZONE:-America/New_York}
|
||||||
|
- SMTP_SERVER=${SMTP_SERVER}
|
||||||
|
- SMTP_PORT=${SMTP_PORT:-587}
|
||||||
|
- SMTP_USERNAME=${SMTP_USERNAME}
|
||||||
|
- SMTP_PASSWORD=${SMTP_PASSWORD}
|
||||||
|
- DOMAIN=${DOMAIN}
|
||||||
|
- SERVER_HOSTNAME=${SERVER_HOSTNAME}
|
||||||
|
- SMTP_NETWORKS=${SMTP_NETWORKS}
|
||||||
|
- SMTP_HEADER_TAG=${SMTP_HEADER_TAG}
|
||||||
|
- DEBUG=${DEBUG:-no}
|
||||||
|
volumes:
|
||||||
|
- "${DATA_FOLDER:-.}/logs:/var/log"
|
||||||
|
- "${DATA_FOLDER:-.}/mail:/var/mail"
|
||||||
|
- "${DATA_FOLDER:-.}/spool:/var/spool/postfix"
|
||||||
|
networks:
|
||||||
|
- postfix-network
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
labels: "service=postfix-relay"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "postfix", "status"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
postfix-network:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: 172.28.0.0/16
|
||||||
|
gateway: 172.28.0.1
|
||||||
+109
-6
@@ -1,8 +1,111 @@
|
|||||||
|
# ============================================
|
||||||
|
# Postfix SMTP Relay - Environment Variables
|
||||||
|
# ============================================
|
||||||
|
# Copy this file to .env and configure your settings
|
||||||
|
# Supports: Maileroo, Mailtrap, SendGrid, and generic SMTP servers
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# General Configuration
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# Timezone (default: America/New_York)
|
||||||
TIMEZONE='America/New_York'
|
TIMEZONE='America/New_York'
|
||||||
SMTP_SERVER='smtp.example.com'
|
|
||||||
SERVER_HOSTNAME=server_name
|
# Domain for outgoing mail
|
||||||
|
DOMAIN=example.com
|
||||||
|
|
||||||
|
# Server hostname (optional - defaults to container hostname)
|
||||||
|
SERVER_HOSTNAME=mail.example.com
|
||||||
|
|
||||||
|
# Port to expose on host (default: 25)
|
||||||
|
SMTP_LISTEN_PORT=25
|
||||||
|
|
||||||
|
# Data folder for logs, mail, and spool (default: current directory)
|
||||||
|
DATA_FOLDER=./data
|
||||||
|
|
||||||
|
# Optional: Custom networks to allow relay (comma-separated CIDR notation)
|
||||||
|
# SMTP_NETWORKS=192.168.1.0/24,10.0.0.0/8
|
||||||
|
|
||||||
|
# Optional: Add custom header tag to relayed messages
|
||||||
|
# SMTP_HEADER_TAG=MyRelay
|
||||||
|
|
||||||
|
# Debug mode (yes/no) - enables verbose logging
|
||||||
|
DEBUG=no
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# SMTP Provider Configuration
|
||||||
|
# Choose ONE of the following configurations
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# Option 1: Maileroo (Current Configuration)
|
||||||
|
# --------------------------------------------
|
||||||
|
SMTP_SERVER='smtp.maileroo.com'
|
||||||
SMTP_PORT=587
|
SMTP_PORT=587
|
||||||
DOMAIN=smtp_domain
|
SMTP_USERNAME=noreply@example.com
|
||||||
SMTP_USERNAME=apikey
|
SMTP_PASSWORD=your_maileroo_password_here
|
||||||
SMTP_PASSWORD='api_key'
|
|
||||||
DATA_FOLDER='Local data folder'
|
# --------------------------------------------
|
||||||
|
# Option 2: Mailtrap
|
||||||
|
# --------------------------------------------
|
||||||
|
# SMTP_SERVER='live.smtp.mailtrap.io'
|
||||||
|
# SMTP_PORT=587
|
||||||
|
# SMTP_USERNAME=your_mailtrap_username
|
||||||
|
# SMTP_PASSWORD=your_mailtrap_password
|
||||||
|
|
||||||
|
# For Mailtrap Sandbox (testing):
|
||||||
|
# SMTP_SERVER='sandbox.smtp.mailtrap.io'
|
||||||
|
# SMTP_PORT=2525
|
||||||
|
# SMTP_USERNAME=your_mailtrap_sandbox_username
|
||||||
|
# SMTP_PASSWORD=your_mailtrap_sandbox_password
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# Option 3: SendGrid
|
||||||
|
# --------------------------------------------
|
||||||
|
# SMTP_SERVER='smtp.sendgrid.net'
|
||||||
|
# SMTP_PORT=587
|
||||||
|
# SMTP_USERNAME=apikey
|
||||||
|
# SMTP_PASSWORD=your_sendgrid_api_key_here
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# Option 4: Generic SMTP Server
|
||||||
|
# --------------------------------------------
|
||||||
|
# SMTP_SERVER='smtp.example.com'
|
||||||
|
# SMTP_PORT=587
|
||||||
|
# SMTP_USERNAME=your_username
|
||||||
|
# SMTP_PASSWORD=your_password
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# Option 5: Gmail (requires app password)
|
||||||
|
# --------------------------------------------
|
||||||
|
# SMTP_SERVER='smtp.gmail.com'
|
||||||
|
# SMTP_PORT=587
|
||||||
|
# SMTP_USERNAME=your_email@gmail.com
|
||||||
|
# SMTP_PASSWORD=your_app_password
|
||||||
|
|
||||||
|
# --------------------------------------------
|
||||||
|
# Option 6: Office 365 / Outlook
|
||||||
|
# --------------------------------------------
|
||||||
|
# SMTP_SERVER='smtp.office365.com'
|
||||||
|
# SMTP_PORT=587
|
||||||
|
# SMTP_USERNAME=your_email@outlook.com
|
||||||
|
# SMTP_PASSWORD=your_password
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Notes
|
||||||
|
# ============================================
|
||||||
|
#
|
||||||
|
# 1. The container automatically detects /16 subnet for relay
|
||||||
|
# Additional networks can be added via SMTP_NETWORKS
|
||||||
|
#
|
||||||
|
# 2. All logs are sent to stderr and visible via:
|
||||||
|
# docker logs postfix-relay
|
||||||
|
#
|
||||||
|
# 3. TLS is automatically enabled for known providers
|
||||||
|
# (Maileroo, Mailtrap, SendGrid)
|
||||||
|
#
|
||||||
|
# 4. Health check monitors Postfix status every 30 seconds
|
||||||
|
#
|
||||||
|
# 5. For SendGrid, username must be "apikey" (literal string)
|
||||||
|
#
|
||||||
|
# ============================================
|
||||||
@@ -1,9 +1,26 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Redirect all output to stderr for docker logs
|
||||||
|
exec 1>&2
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "Postfix SMTP Relay Configuration"
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
[ "${DEBUG}" == "yes" ] && set -x
|
[ "${DEBUG}" == "yes" ] && set -x
|
||||||
|
|
||||||
/usr/lib/postfix/post-install meta_directory=/etc/postfix create-missing
|
# Set timezone
|
||||||
/usr/lib/postfix/master
|
if [ -n "${TIMEZONE}" ]; then
|
||||||
|
echo "Setting timezone to: ${TIMEZONE}"
|
||||||
|
cp /usr/share/zoneinfo/${TIMEZONE} /etc/localtime
|
||||||
|
echo "${TIMEZONE}" > /etc/timezone
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Initialize postfix directories (Alpine-specific)
|
||||||
|
# Postfix on Alpine doesn't use post-install in the same way
|
||||||
|
# The directories are already created during package installation
|
||||||
|
|
||||||
function add_config_value() {
|
function add_config_value() {
|
||||||
local key=${1}
|
local key=${1}
|
||||||
@@ -12,77 +29,191 @@ function add_config_value() {
|
|||||||
[ "${key}" == "" ] && echo "ERROR: No key set !!" && exit 1
|
[ "${key}" == "" ] && echo "ERROR: No key set !!" && exit 1
|
||||||
[ "${value}" == "" ] && echo "ERROR: No value set !!" && exit 1
|
[ "${value}" == "" ] && echo "ERROR: No value set !!" && exit 1
|
||||||
|
|
||||||
echo "Setting configuration option ${key} with value: ${value}"
|
echo " Setting: ${key} = ${value}"
|
||||||
postconf -e "${key} = ${value}"
|
postconf -e "${key} = ${value}"
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -z "${SMTP_SERVER}" ] && echo "SMTP_SERVER is not set" && exit 1
|
# Validate required environment variables
|
||||||
[ -z "${SMTP_PORT}" ] && echo "SMTP_PORT is not set" && exit 1
|
[ -z "${SMTP_SERVER}" ] && echo "ERROR: SMTP_SERVER is not set" && exit 1
|
||||||
[ -z "${SMTP_USERNAME}" ] && echo "SMTP_USERNAME is not set" && exit 1
|
[ -z "${SMTP_PORT}" ] && echo "ERROR: SMTP_PORT is not set" && exit 1
|
||||||
[ -z "${SMTP_PASSWORD}" ] && echo "SMTP_PASSWORD is not set" && exit 1
|
[ -z "${SMTP_USERNAME}" ] && echo "ERROR: SMTP_USERNAME is not set" && exit 1
|
||||||
|
[ -z "${SMTP_PASSWORD}" ] && echo "ERROR: SMTP_PASSWORD is not set" && exit 1
|
||||||
|
|
||||||
#Check for subnet restrictions
|
# Detect SMTP provider and set defaults
|
||||||
nets='127.0.0.1, 172.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16'
|
SMTP_PROVIDER="generic"
|
||||||
if [ ! -z "${SMTP_NETWORKS}" ]; then
|
if [[ "${SMTP_SERVER}" == *"mailtrap.io"* ]]; then
|
||||||
for i in $(sed 's/,/\ /g' <<<$SMTP_NETWORKS); do
|
SMTP_PROVIDER="mailtrap"
|
||||||
if grep -Eq "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}" <<<$i ; then
|
echo "Detected provider: Mailtrap"
|
||||||
nets+=", $i"
|
elif [[ "${SMTP_SERVER}" == *"sendgrid"* ]]; then
|
||||||
|
SMTP_PROVIDER="sendgrid"
|
||||||
|
echo "Detected provider: SendGrid"
|
||||||
|
elif [[ "${SMTP_SERVER}" == *"maileroo"* ]]; then
|
||||||
|
SMTP_PROVIDER="maileroo"
|
||||||
|
echo "Detected provider: Maileroo"
|
||||||
else
|
else
|
||||||
echo "$i is not in proper IPv4 subnet format. Ignoring."
|
echo "Using generic SMTP provider: ${SMTP_SERVER}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get local network subnet - allow override via environment variable
|
||||||
|
if [ -z "${LOCAL_NETWORK}" ]; then
|
||||||
|
# Auto-detect and use /16 by default
|
||||||
|
LOCAL_NETWORK=$(ip route | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+' | head -1 | awk '{print $1}')
|
||||||
|
if [ -z "$LOCAL_NETWORK" ]; then
|
||||||
|
LOCAL_IP=$(hostname -i | grep -E -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
|
||||||
|
if [ -n "$LOCAL_IP" ]; then
|
||||||
|
# Extract first two octets for /16 network
|
||||||
|
NETWORK_PREFIX=$(echo $LOCAL_IP | cut -d. -f1-2)
|
||||||
|
LOCAL_NETWORK="${NETWORK_PREFIX}.0.0/16"
|
||||||
|
else
|
||||||
|
LOCAL_NETWORK="172.16.0.0/16"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "Auto-detected local network: ${LOCAL_NETWORK}"
|
||||||
|
else
|
||||||
|
echo "Using provided LOCAL_NETWORK: ${LOCAL_NETWORK}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build mynetworks - always include localhost and detected local network
|
||||||
|
nets="127.0.0.0/8, [::1]/128, ${LOCAL_NETWORK}"
|
||||||
|
|
||||||
|
# Add custom networks if specified
|
||||||
|
if [ ! -z "${SMTP_NETWORKS}" ]; then
|
||||||
|
echo "Adding custom networks..."
|
||||||
|
for i in $(sed 's/,/ /g' <<<$SMTP_NETWORKS); do
|
||||||
|
if grep -Eq "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}" <<<$i ; then
|
||||||
|
nets="${nets}, $i"
|
||||||
|
echo " Added network: $i"
|
||||||
|
else
|
||||||
|
echo " WARNING: $i is not in proper IPv4 subnet format. Ignoring."
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set needed config options
|
echo ""
|
||||||
add_config_value "myhostname" ${SERVER_HOSTNAME}
|
echo "Allowed networks: ${nets}"
|
||||||
add_config_value "mydomain" ${DOMAIN}
|
echo ""
|
||||||
|
|
||||||
|
# Set hostname and domain defaults
|
||||||
|
SERVER_HOSTNAME_DEFAULT=$(hostname -f)
|
||||||
|
DOMAIN_DEFAULT=$(hostname -d)
|
||||||
|
|
||||||
|
# Use provided values or defaults
|
||||||
|
SERVER_HOSTNAME=${SERVER_HOSTNAME:-${SERVER_HOSTNAME_DEFAULT}}
|
||||||
|
DOMAIN=${DOMAIN:-${DOMAIN_DEFAULT}}
|
||||||
|
|
||||||
|
echo "Configuring Postfix..."
|
||||||
|
echo "----------------------------------------"
|
||||||
|
|
||||||
|
# Basic configuration
|
||||||
|
add_config_value "myhostname" "${SERVER_HOSTNAME}"
|
||||||
|
add_config_value "mydomain" "${DOMAIN}"
|
||||||
add_config_value "mydestination" '$myhostname'
|
add_config_value "mydestination" '$myhostname'
|
||||||
add_config_value "myorigin" '$mydomain'
|
add_config_value "myorigin" '$mydomain'
|
||||||
|
add_config_value "mynetworks" "${nets}"
|
||||||
|
add_config_value "inet_interfaces" "all"
|
||||||
|
add_config_value "inet_protocols" "ipv4"
|
||||||
|
|
||||||
|
# Relay configuration
|
||||||
add_config_value "relayhost" "[${SMTP_SERVER}]:${SMTP_PORT}"
|
add_config_value "relayhost" "[${SMTP_SERVER}]:${SMTP_PORT}"
|
||||||
|
add_config_value "relay_domains" "*"
|
||||||
|
|
||||||
|
# SASL Authentication
|
||||||
add_config_value "smtp_sasl_auth_enable" "yes"
|
add_config_value "smtp_sasl_auth_enable" "yes"
|
||||||
add_config_value "smtp_sasl_password_maps" "lmdb:/etc/postfix/sasl_passwd"
|
add_config_value "smtp_sasl_password_maps" "lmdb:/etc/postfix/sasl_passwd"
|
||||||
add_config_value "smtp_sasl_security_options" "noanonymous"
|
add_config_value "smtp_sasl_security_options" "noanonymous"
|
||||||
add_config_value "smtp_sasl_tls_security_options" "noanonymous"
|
add_config_value "smtp_sasl_tls_security_options" "noanonymous"
|
||||||
|
add_config_value "smtp_sasl_mechanism_filter" "plain, login"
|
||||||
|
|
||||||
|
# TLS configuration
|
||||||
|
if [ "${SMTP_PROVIDER}" == "sendgrid" ] || [ "${SMTP_PROVIDER}" == "mailtrap" ] || [ "${SMTP_PROVIDER}" == "maileroo" ]; then
|
||||||
|
add_config_value "smtp_use_tls" "yes"
|
||||||
add_config_value "smtp_tls_security_level" "encrypt"
|
add_config_value "smtp_tls_security_level" "encrypt"
|
||||||
|
add_config_value "smtp_tls_CAfile" "/etc/ssl/certs/ca-certificates.crt"
|
||||||
|
add_config_value "smtp_tls_session_cache_database" "btree:\${data_directory}/smtp_scache"
|
||||||
|
add_config_value "smtp_tls_loglevel" "1"
|
||||||
|
else
|
||||||
|
add_config_value "smtp_tls_security_level" "may"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Size limits
|
||||||
add_config_value "header_size_limit" "4096000"
|
add_config_value "header_size_limit" "4096000"
|
||||||
add_config_value "smtpd_sasl_local_domain" ${DOMAIN}
|
add_config_value "mailbox_size_limit" "0"
|
||||||
add_config_value "smtpd_recipient_restrictions" "permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination"
|
add_config_value "message_size_limit" "52428800"
|
||||||
add_config_value "mailbox_size_limit" "256000000"
|
add_config_value "recipient_delimiter" "+"
|
||||||
|
|
||||||
# Create sasl_passwd file with auth credentials
|
# Relay restrictions
|
||||||
if [ ! -f /etc/postfix/sasl_passwd ]; then
|
add_config_value "smtpd_relay_restrictions" "permit_mynetworks, reject_unauth_destination"
|
||||||
grep -q "${SMTP_SERVER}" /etc/postfix/sasl_passwd > /dev/null 2>&1
|
add_config_value "smtpd_recipient_restrictions" "permit_mynetworks, reject_unauth_destination"
|
||||||
if [ $? -gt 0 ]; then
|
add_config_value "smtpd_sasl_local_domain" "${DOMAIN}"
|
||||||
echo "Adding SASL authentication configuration"
|
|
||||||
echo "[${SMTP_SERVER}]:${SMTP_PORT} ${SMTP_USERNAME}:${SMTP_PASSWORD}" >> /etc/postfix/sasl_passwd
|
# Logging configuration - send logs to stdout/stderr
|
||||||
|
add_config_value "maillog_file" "/dev/stdout"
|
||||||
|
add_config_value "maillog_file_prefixes" "/var, /dev"
|
||||||
|
|
||||||
|
# Queue settings
|
||||||
|
add_config_value "maximal_queue_lifetime" "1d"
|
||||||
|
add_config_value "bounce_queue_lifetime" "1d"
|
||||||
|
add_config_value "queue_run_delay" "300s"
|
||||||
|
add_config_value "minimal_backoff_time" "300s"
|
||||||
|
add_config_value "maximal_backoff_time" "4000s"
|
||||||
|
|
||||||
|
# Debug settings (enable if DEBUG=yes)
|
||||||
|
if [ "${DEBUG}" == "yes" ]; then
|
||||||
|
add_config_value "debug_peer_level" "2"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create SASL password file
|
||||||
|
echo "Configuring SASL authentication..."
|
||||||
|
echo "[${SMTP_SERVER}]:${SMTP_PORT} ${SMTP_USERNAME}:${SMTP_PASSWORD}" > /etc/postfix/sasl_passwd
|
||||||
|
chmod 600 /etc/postfix/sasl_passwd
|
||||||
postmap /etc/postfix/sasl_passwd
|
postmap /etc/postfix/sasl_passwd
|
||||||
fi
|
# Set permissions on the generated database file (may have different extensions)
|
||||||
fi
|
chmod 600 /etc/postfix/sasl_passwd.* 2>/dev/null || true
|
||||||
|
echo " SASL credentials configured for ${SMTP_SERVER}:${SMTP_PORT}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
#Set header tag
|
# Set header tag if specified
|
||||||
if [ ! -z "${SMTP_HEADER_TAG}" ]; then
|
if [ ! -z "${SMTP_HEADER_TAG}" ]; then
|
||||||
|
echo "Setting SMTP header tag: ${SMTP_HEADER_TAG}"
|
||||||
postconf -e "header_checks = regexp:/etc/postfix/header_tag"
|
postconf -e "header_checks = regexp:/etc/postfix/header_tag"
|
||||||
echo -e "/^MIME-Version:/i PREPEND RelayTag: $SMTP_HEADER_TAG\n/^Content-Transfer-Encoding:/i PREPEND RelayTag: $SMTP_HEADER_TAG" > /etc/postfix/header_tag
|
echo -e "/^MIME-Version:/i PREPEND RelayTag: $SMTP_HEADER_TAG\n/^Content-Transfer-Encoding:/i PREPEND RelayTag: $SMTP_HEADER_TAG" > /etc/postfix/header_tag
|
||||||
echo "Setting configuration option SMTP_HEADER_TAG with value: ${SMTP_HEADER_TAG}"
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Clean up old PID file if mounting /var/spool/postfix
|
||||||
add_config_value "mynetworks" "${nets}"
|
echo "Cleaning up old PID files..."
|
||||||
|
|
||||||
#Start services
|
|
||||||
|
|
||||||
# If host mounting /var/spool/postfix, we need to delete old pid file before
|
|
||||||
# starting services
|
|
||||||
rm -f /var/spool/postfix/pid/master.pid
|
rm -f /var/spool/postfix/pid/master.pid
|
||||||
|
|
||||||
|
# Validate postfix configuration
|
||||||
|
echo "Validating Postfix configuration..."
|
||||||
postconf -c /etc/postfix/
|
postconf -c /etc/postfix/
|
||||||
|
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
echo "Postfix configuration error, refusing to start."
|
echo ""
|
||||||
|
echo "========================================"
|
||||||
|
echo "ERROR: Postfix configuration error!"
|
||||||
|
echo "========================================"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
|
||||||
postfix -c /etc/postfix/ start
|
|
||||||
sleep 126144000
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ENTERYPOINT /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
|
echo ""
|
||||||
|
echo "========================================"
|
||||||
|
echo "Postfix configuration completed successfully"
|
||||||
|
echo "========================================"
|
||||||
|
echo "Provider: ${SMTP_PROVIDER}"
|
||||||
|
echo "Relay host: ${SMTP_SERVER}:${SMTP_PORT}"
|
||||||
|
echo "Hostname: ${SERVER_HOSTNAME}"
|
||||||
|
echo "Domain: ${DOMAIN}"
|
||||||
|
echo "Networks: ${nets}"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Start postfix in foreground mode
|
||||||
|
echo "Starting Postfix in foreground mode..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run postfix in foreground - this will handle all logging to stdout/stderr
|
||||||
|
exec postfix start-fg
|
||||||
+188
@@ -0,0 +1,188 @@
|
|||||||
|
.PHONY: help build up down restart logs shell test clean status queue config
|
||||||
|
|
||||||
|
# Change to parent directory for docker-compose commands
|
||||||
|
COMPOSE=cd .. && docker-compose
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
help:
|
||||||
|
@echo "Docker Postfix SMTP Relay - Makefile Commands"
|
||||||
|
@echo "=============================================="
|
||||||
|
@echo ""
|
||||||
|
@echo "Setup and Build:"
|
||||||
|
@echo " make build - Build the Docker image"
|
||||||
|
@echo " make up - Start the container"
|
||||||
|
@echo " make down - Stop the container"
|
||||||
|
@echo " make restart - Restart the container"
|
||||||
|
@echo ""
|
||||||
|
@echo "Monitoring:"
|
||||||
|
@echo " make logs - View container logs (follow)"
|
||||||
|
@echo " make logs-tail - View last 100 lines"
|
||||||
|
@echo " make status - Show container and Postfix status"
|
||||||
|
@echo " make queue - View mail queue"
|
||||||
|
@echo " make health - Check container health"
|
||||||
|
@echo ""
|
||||||
|
@echo "Maintenance:"
|
||||||
|
@echo " make shell - Open shell in container"
|
||||||
|
@echo " make config - Show Postfix configuration"
|
||||||
|
@echo " make test - Send test email (auto-detects container)"
|
||||||
|
@echo " Usage: make test TO=user@example.com [FROM=sender@domain.com]"
|
||||||
|
@echo " make flush - Flush mail queue"
|
||||||
|
@echo " make check - Check Postfix configuration"
|
||||||
|
@echo ""
|
||||||
|
@echo "Cleanup:"
|
||||||
|
@echo " make clean - Remove container and volumes"
|
||||||
|
@echo " make clean-all - Remove everything including images"
|
||||||
|
@echo ""
|
||||||
|
@echo "Advanced:"
|
||||||
|
@echo " make debug - Start with debug mode enabled"
|
||||||
|
@echo " make validate - Validate environment file"
|
||||||
|
@echo " make stats - Show real-time stats"
|
||||||
|
@echo ""
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
build:
|
||||||
|
@echo "Building Docker image..."
|
||||||
|
@$(COMPOSE) build
|
||||||
|
|
||||||
|
# Start the container
|
||||||
|
up:
|
||||||
|
@echo "Starting Postfix relay..."
|
||||||
|
@$(COMPOSE) up -d
|
||||||
|
@echo "Waiting for container to be healthy..."
|
||||||
|
@sleep 5
|
||||||
|
@make status
|
||||||
|
|
||||||
|
# Stop the container
|
||||||
|
down:
|
||||||
|
@echo "Stopping Postfix relay..."
|
||||||
|
@$(COMPOSE) down
|
||||||
|
|
||||||
|
# Restart the container
|
||||||
|
restart: down up
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
logs:
|
||||||
|
@$(COMPOSE) logs -f
|
||||||
|
|
||||||
|
# View last 100 lines of logs
|
||||||
|
logs-tail:
|
||||||
|
@$(COMPOSE) logs --tail=100
|
||||||
|
|
||||||
|
# Open shell in container
|
||||||
|
shell:
|
||||||
|
@$(COMPOSE) exec postfix bash
|
||||||
|
|
||||||
|
# Show container and Postfix status
|
||||||
|
status:
|
||||||
|
@echo "Container Status:"
|
||||||
|
@echo "================="
|
||||||
|
@docker ps --filter name=postfix-relay --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||||
|
@echo ""
|
||||||
|
@echo "Postfix Status:"
|
||||||
|
@echo "==============="
|
||||||
|
@$(COMPOSE) exec postfix postfix status || echo "Container not running"
|
||||||
|
|
||||||
|
# View mail queue
|
||||||
|
queue:
|
||||||
|
@echo "Mail Queue:"
|
||||||
|
@echo "==========="
|
||||||
|
@$(COMPOSE) exec postfix postqueue -p
|
||||||
|
|
||||||
|
# Flush mail queue
|
||||||
|
flush:
|
||||||
|
@echo "Flushing mail queue..."
|
||||||
|
@$(COMPOSE) exec postfix postqueue -f
|
||||||
|
@echo "Queue flushed"
|
||||||
|
|
||||||
|
# View Postfix configuration
|
||||||
|
config:
|
||||||
|
@echo "Postfix Configuration:"
|
||||||
|
@echo "====================="
|
||||||
|
@$(COMPOSE) exec postfix postconf -n
|
||||||
|
|
||||||
|
# Check Postfix configuration
|
||||||
|
check:
|
||||||
|
@echo "Checking Postfix configuration..."
|
||||||
|
@$(COMPOSE) exec postfix postfix check
|
||||||
|
@$(COMPOSE) exec postfix postconf -c /etc/postfix/
|
||||||
|
@echo "Configuration check complete"
|
||||||
|
|
||||||
|
# Send test email
|
||||||
|
test:
|
||||||
|
@if [ -z "$(TO)" ]; then \
|
||||||
|
echo "Usage: make test TO=recipient@example.com [FROM=sender@domain.com] [SUBJECT='Test Email']"; \
|
||||||
|
echo ""; \
|
||||||
|
echo "Examples:"; \
|
||||||
|
echo " make test TO=user@example.com"; \
|
||||||
|
echo " make test TO=user@example.com FROM=noreply@mydomain.com"; \
|
||||||
|
echo " make test TO=user@example.com FROM=sender@domain.com SUBJECT='My Test'"; \
|
||||||
|
echo ""; \
|
||||||
|
echo "Note: Container is auto-detected from docker-postfix-postfix image"; \
|
||||||
|
echo " FROM defaults to noreply@<DOMAIN> if not specified"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@if [ -n "$(CONTAINER)" ]; then \
|
||||||
|
./test-email.sh $(CONTAINER) $(TO) $(FROM) $(SUBJECT); \
|
||||||
|
else \
|
||||||
|
./test-email.sh $(TO) $(FROM) $(SUBJECT); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate environment file
|
||||||
|
validate:
|
||||||
|
@echo "Validating .env file..."
|
||||||
|
@if [ ! -f ../.env ]; then \
|
||||||
|
echo "ERROR: .env file not found. Copy env.sample to .env in parent directory"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@grep -q "SMTP_SERVER=" ../.env || (echo "ERROR: SMTP_SERVER not set" && exit 1)
|
||||||
|
@grep -q "SMTP_PORT=" ../.env || (echo "ERROR: SMTP_PORT not set" && exit 1)
|
||||||
|
@grep -q "SMTP_USERNAME=" ../.env || (echo "ERROR: SMTP_USERNAME not set" && exit 1)
|
||||||
|
@grep -q "SMTP_PASSWORD=" ../.env || (echo "ERROR: SMTP_PASSWORD not set" && exit 1)
|
||||||
|
@grep -q "DOMAIN=" ../.env || (echo "ERROR: DOMAIN not set" && exit 1)
|
||||||
|
@echo "Environment file validation passed"
|
||||||
|
|
||||||
|
# Clean up (remove container and volumes)
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning up containers and volumes..."
|
||||||
|
@$(COMPOSE) down -v
|
||||||
|
@echo "Cleaning local data directories..."
|
||||||
|
@cd .. && rm -rf data logs mail spool
|
||||||
|
@echo "Cleanup complete"
|
||||||
|
|
||||||
|
# Clean everything including images
|
||||||
|
clean-all: clean
|
||||||
|
@echo "Removing Docker images..."
|
||||||
|
@$(COMPOSE) down --rmi all
|
||||||
|
@echo "Complete cleanup finished"
|
||||||
|
|
||||||
|
# Show queue details
|
||||||
|
queue-detail:
|
||||||
|
@echo "Detailed Queue Information:"
|
||||||
|
@echo "=========================="
|
||||||
|
@$(COMPOSE) exec postfix sh -c "postqueue -p | tail -n 1"
|
||||||
|
|
||||||
|
# Delete all queued messages
|
||||||
|
queue-delete:
|
||||||
|
@echo "WARNING: This will delete ALL messages in the queue!"
|
||||||
|
@read -p "Are you sure? (yes/no): " confirm; \
|
||||||
|
if [ "$$confirm" = "yes" ]; then \
|
||||||
|
$(COMPOSE) exec postfix postsuper -d ALL; \
|
||||||
|
echo "All queued messages deleted"; \
|
||||||
|
else \
|
||||||
|
echo "Cancelled"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable debug mode
|
||||||
|
debug:
|
||||||
|
@echo "Restarting with DEBUG mode enabled..."
|
||||||
|
@$(COMPOSE) down
|
||||||
|
@cd .. && DEBUG=yes docker-compose up
|
||||||
|
|
||||||
|
# Show real-time statistics
|
||||||
|
stats:
|
||||||
|
@docker stats postfix-relay
|
||||||
|
|
||||||
|
# Run health check
|
||||||
|
health:
|
||||||
|
@echo "Running health check..."
|
||||||
|
@docker inspect postfix-relay --format='{{.State.Health.Status}}' 2>/dev/null || echo "Container not running"
|
||||||
Executable
+200
@@ -0,0 +1,200 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Parse arguments flexibly
|
||||||
|
# Supports: recipient [from] [subject]
|
||||||
|
# Or: container recipient [from] [subject]
|
||||||
|
CONTAINER_NAME=""
|
||||||
|
RECIPIENT=""
|
||||||
|
FROM_EMAIL=""
|
||||||
|
SUBJECT="Test Email from Postfix Relay"
|
||||||
|
|
||||||
|
# Check if first argument looks like an email
|
||||||
|
if [[ "$1" =~ @.*\. ]]; then
|
||||||
|
# First arg is email - it's the recipient
|
||||||
|
RECIPIENT="${1}"
|
||||||
|
FROM_EMAIL="${2}"
|
||||||
|
SUBJECT="${3:-Test Email from Postfix Relay}"
|
||||||
|
else
|
||||||
|
# First arg is not email - assume it's container name
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
CONTAINER_NAME="${1}"
|
||||||
|
RECIPIENT="${2}"
|
||||||
|
FROM_EMAIL="${3}"
|
||||||
|
SUBJECT="${4:-Test Email from Postfix Relay}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to print colored messages
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}ERROR: $1${NC}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}SUCCESS: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${YELLOW}INFO: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show usage if recipient is not provided
|
||||||
|
if [ -z "$RECIPIENT" ]; then
|
||||||
|
echo "Usage: $0 RECIPIENT_EMAIL [FROM_EMAIL] [SUBJECT]"
|
||||||
|
echo " or: $0 CONTAINER_NAME RECIPIENT_EMAIL [FROM_EMAIL] [SUBJECT]"
|
||||||
|
echo ""
|
||||||
|
echo "Arguments:"
|
||||||
|
echo " RECIPIENT_EMAIL - Email address to send test email to (required)"
|
||||||
|
echo " FROM_EMAIL - From email address (optional, default: noreply@<domain>)"
|
||||||
|
echo " SUBJECT - Email subject (default: 'Test Email from Postfix Relay')"
|
||||||
|
echo " CONTAINER_NAME - Docker container name (optional, auto-detected)"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 user@example.com"
|
||||||
|
echo " $0 user@example.com sender@mydomain.com"
|
||||||
|
echo " $0 user@example.com sender@mydomain.com 'My Test Email'"
|
||||||
|
echo " $0 my-postfix user@example.com sender@mydomain.com"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Auto-detect container name if not provided
|
||||||
|
if [ -z "$CONTAINER_NAME" ]; then
|
||||||
|
print_info "Auto-detecting container..."
|
||||||
|
|
||||||
|
# Try to find container by image name pattern
|
||||||
|
CONTAINER_NAME=$(docker ps --filter "ancestor=docker-postfix-postfix" --format '{{.Names}}' | head -n 1)
|
||||||
|
|
||||||
|
# Fallback: try common naming patterns
|
||||||
|
if [ -z "$CONTAINER_NAME" ]; then
|
||||||
|
CONTAINER_NAME=$(docker ps --filter "name=postfix" --format '{{.Names}}' | head -n 1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$CONTAINER_NAME" ]; then
|
||||||
|
print_error "Could not auto-detect container. Please specify container name."
|
||||||
|
echo ""
|
||||||
|
echo "Available containers:"
|
||||||
|
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 CONTAINER_NAME RECIPIENT_EMAIL"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Detected container: ${CONTAINER_NAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if container exists
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
|
print_error "Container '${CONTAINER_NAME}' is not running"
|
||||||
|
echo ""
|
||||||
|
echo "Available containers:"
|
||||||
|
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Container: ${CONTAINER_NAME}"
|
||||||
|
|
||||||
|
# Get the port mapping for the container
|
||||||
|
PORT_MAPPING=$(docker port "${CONTAINER_NAME}" 25 2>/dev/null | head -n 1)
|
||||||
|
|
||||||
|
if [ -z "$PORT_MAPPING" ]; then
|
||||||
|
print_error "Could not determine port mapping for container '${CONTAINER_NAME}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract host and port from mapping (format: 0.0.0.0:25 or 127.0.0.1:25)
|
||||||
|
HOST=$(echo "$PORT_MAPPING" | cut -d: -f1)
|
||||||
|
PORT=$(echo "$PORT_MAPPING" | cut -d: -f2)
|
||||||
|
|
||||||
|
# Convert 0.0.0.0 to 127.0.0.1 for local communication
|
||||||
|
if [ "$HOST" = "0.0.0.0" ]; then
|
||||||
|
HOST="127.0.0.1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set default FROM email if not provided
|
||||||
|
if [ -z "$FROM_EMAIL" ]; then
|
||||||
|
# Try to get domain from container environment or use hostname
|
||||||
|
DOMAIN=$(docker exec "$CONTAINER_NAME" printenv DOMAIN 2>/dev/null || echo "relay.local")
|
||||||
|
FROM_EMAIL="noreply@${DOMAIN}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "SMTP Server: ${HOST}:${PORT}"
|
||||||
|
print_info "From: ${FROM_EMAIL}"
|
||||||
|
print_info "Recipient: ${RECIPIENT}"
|
||||||
|
print_info "Subject: ${SUBJECT}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Generate email body with timestamp
|
||||||
|
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S %Z")
|
||||||
|
EMAIL_BODY="This is a test email sent from the Postfix SMTP relay.
|
||||||
|
|
||||||
|
Container: ${CONTAINER_NAME}
|
||||||
|
Sent at: ${TIMESTAMP}
|
||||||
|
SMTP Server: ${HOST}:${PORT}
|
||||||
|
|
||||||
|
If you received this email, your Postfix relay is working correctly!
|
||||||
|
|
||||||
|
---
|
||||||
|
Automated test email"
|
||||||
|
|
||||||
|
print_info "Sending test email..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Method 1: Try using sendmail directly (most reliable for Postfix)
|
||||||
|
print_info "Attempting to send via sendmail..."
|
||||||
|
|
||||||
|
SENDMAIL_OUTPUT=$(docker exec -i "$CONTAINER_NAME" sendmail -v -f "$FROM_EMAIL" "$RECIPIENT" 2>&1 << EOFMAIL
|
||||||
|
From: ${FROM_EMAIL}
|
||||||
|
To: ${RECIPIENT}
|
||||||
|
Subject: ${SUBJECT}
|
||||||
|
|
||||||
|
${EMAIL_BODY}
|
||||||
|
EOFMAIL
|
||||||
|
)
|
||||||
|
SENDMAIL_EXIT=$?
|
||||||
|
|
||||||
|
if [ $SENDMAIL_EXIT -eq 0 ]; then
|
||||||
|
print_success "Email queued successfully via sendmail"
|
||||||
|
echo "$SENDMAIL_OUTPUT" | grep -i "queued\|sent" || true
|
||||||
|
else
|
||||||
|
print_error "Sendmail method failed"
|
||||||
|
echo "Output: $SENDMAIL_OUTPUT"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Method 2: Try using mailx/mail command
|
||||||
|
print_info "Trying alternative method using mail command..."
|
||||||
|
|
||||||
|
MAIL_OUTPUT=$(docker exec "$CONTAINER_NAME" sh -c "
|
||||||
|
echo '${EMAIL_BODY}' | mail -v -s '${SUBJECT}' -r '${FROM_EMAIL}' '${RECIPIENT}' 2>&1
|
||||||
|
")
|
||||||
|
MAIL_EXIT=$?
|
||||||
|
|
||||||
|
if [ $MAIL_EXIT -eq 0 ]; then
|
||||||
|
print_success "Email queued successfully via mail command"
|
||||||
|
else
|
||||||
|
print_error "Mail command failed"
|
||||||
|
echo "Output: $MAIL_OUTPUT"
|
||||||
|
echo ""
|
||||||
|
print_info "Check container logs for more details:"
|
||||||
|
echo " docker logs $CONTAINER_NAME"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_info "Checking mail queue..."
|
||||||
|
docker exec "$CONTAINER_NAME" postqueue -p 2>/dev/null || echo "Queue check not available"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_success "Test complete! Check the recipient mailbox for the test email."
|
||||||
|
echo ""
|
||||||
|
print_info "You can monitor the logs with:"
|
||||||
|
echo " docker logs -f ${CONTAINER_NAME}"
|
||||||
|
echo ""
|
||||||
Executable
+353
@@ -0,0 +1,353 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Postfix SMTP Relay Test Script
|
||||||
|
# This script validates the Postfix relay configuration and sends test emails
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
print_header() {
|
||||||
|
echo -e "\n${BLUE}========================================${NC}"
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
echo -e "${BLUE}========================================${NC}\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}✓ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}✗ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}⚠ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}ℹ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if .env file exists
|
||||||
|
check_env() {
|
||||||
|
print_header "Checking Environment Configuration"
|
||||||
|
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
print_error ".env file not found"
|
||||||
|
print_info "Copy env.sample to .env and configure it"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_success ".env file found"
|
||||||
|
|
||||||
|
# Source the .env file
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Check required variables
|
||||||
|
local required_vars=("SMTP_SERVER" "SMTP_PORT" "SMTP_USERNAME" "SMTP_PASSWORD" "DOMAIN")
|
||||||
|
local missing_vars=0
|
||||||
|
|
||||||
|
for var in "${required_vars[@]}"; do
|
||||||
|
if [ -z "${!var}" ]; then
|
||||||
|
print_error "$var is not set"
|
||||||
|
missing_vars=$((missing_vars + 1))
|
||||||
|
else
|
||||||
|
print_success "$var is set"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $missing_vars -gt 0 ]; then
|
||||||
|
print_error "$missing_vars required variable(s) missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Provider: $SMTP_SERVER:$SMTP_PORT"
|
||||||
|
print_info "Domain: $DOMAIN"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if Docker is running
|
||||||
|
check_docker() {
|
||||||
|
print_header "Checking Docker"
|
||||||
|
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
print_error "Docker is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_success "Docker is installed"
|
||||||
|
|
||||||
|
if ! docker info &> /dev/null; then
|
||||||
|
print_error "Docker daemon is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_success "Docker daemon is running"
|
||||||
|
|
||||||
|
if ! command -v docker-compose &> /dev/null; then
|
||||||
|
print_error "Docker Compose is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_success "Docker Compose is installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
check_container() {
|
||||||
|
print_header "Checking Container Status"
|
||||||
|
|
||||||
|
if ! docker ps --filter name=postfix-relay --format '{{.Names}}' | grep -q postfix-relay; then
|
||||||
|
print_warning "Container is not running"
|
||||||
|
print_info "Starting container..."
|
||||||
|
docker-compose up -d
|
||||||
|
sleep 10
|
||||||
|
fi
|
||||||
|
|
||||||
|
if docker ps --filter name=postfix-relay --format '{{.Names}}' | grep -q postfix-relay; then
|
||||||
|
print_success "Container is running"
|
||||||
|
else
|
||||||
|
print_error "Failed to start container"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check health status
|
||||||
|
health_status=$(docker inspect postfix-relay --format='{{.State.Health.Status}}' 2>/dev/null || echo "unknown")
|
||||||
|
if [ "$health_status" = "healthy" ]; then
|
||||||
|
print_success "Container is healthy"
|
||||||
|
elif [ "$health_status" = "starting" ]; then
|
||||||
|
print_warning "Container is starting..."
|
||||||
|
print_info "Waiting for health check..."
|
||||||
|
sleep 10
|
||||||
|
else
|
||||||
|
print_warning "Health status: $health_status"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check Postfix status
|
||||||
|
check_postfix() {
|
||||||
|
print_header "Checking Postfix Status"
|
||||||
|
|
||||||
|
if docker exec postfix-relay postfix status &> /dev/null; then
|
||||||
|
print_success "Postfix is running"
|
||||||
|
else
|
||||||
|
print_error "Postfix is not running"
|
||||||
|
print_info "Checking logs..."
|
||||||
|
docker logs --tail 50 postfix-relay
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check network connectivity
|
||||||
|
check_network() {
|
||||||
|
print_header "Checking Network Connectivity"
|
||||||
|
|
||||||
|
source .env
|
||||||
|
|
||||||
|
# Check if nc (netcat) is available in container
|
||||||
|
if docker exec postfix-relay which nc &> /dev/null; then
|
||||||
|
if docker exec postfix-relay nc -zv ${SMTP_SERVER} ${SMTP_PORT} 2>&1 | grep -q succeeded; then
|
||||||
|
print_success "Can connect to ${SMTP_SERVER}:${SMTP_PORT}"
|
||||||
|
else
|
||||||
|
print_error "Cannot connect to ${SMTP_SERVER}:${SMTP_PORT}"
|
||||||
|
print_info "Check firewall and network settings"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "netcat not available, skipping connectivity test"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check Postfix configuration
|
||||||
|
check_config() {
|
||||||
|
print_header "Validating Postfix Configuration"
|
||||||
|
|
||||||
|
if docker exec postfix-relay postfix check 2>&1 | grep -q error; then
|
||||||
|
print_error "Postfix configuration has errors"
|
||||||
|
docker exec postfix-relay postfix check
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
print_success "Postfix configuration is valid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show key configuration
|
||||||
|
print_info "Key Configuration Values:"
|
||||||
|
docker exec postfix-relay postconf -n | grep -E "^(myhostname|mydomain|relayhost|mynetworks)" | while read line; do
|
||||||
|
echo " $line"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check mail queue
|
||||||
|
check_queue() {
|
||||||
|
print_header "Checking Mail Queue"
|
||||||
|
|
||||||
|
queue_output=$(docker exec postfix-relay postqueue -p)
|
||||||
|
|
||||||
|
if echo "$queue_output" | grep -q "Mail queue is empty"; then
|
||||||
|
print_success "Mail queue is empty"
|
||||||
|
else
|
||||||
|
print_warning "Mail queue has messages:"
|
||||||
|
echo "$queue_output"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send test email
|
||||||
|
send_test_email() {
|
||||||
|
print_header "Sending Test Email"
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
read -p "Enter recipient email address: " recipient
|
||||||
|
else
|
||||||
|
recipient="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$recipient" ]; then
|
||||||
|
print_error "No recipient provided"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate email format
|
||||||
|
if ! echo "$recipient" | grep -qE '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'; then
|
||||||
|
print_error "Invalid email address format"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Sending test email to: $recipient"
|
||||||
|
|
||||||
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
hostname=$(docker exec postfix-relay hostname)
|
||||||
|
|
||||||
|
test_message="Test email from Postfix SMTP Relay
|
||||||
|
|
||||||
|
Timestamp: $timestamp
|
||||||
|
Hostname: $hostname
|
||||||
|
Container: postfix-relay
|
||||||
|
|
||||||
|
If you receive this email, your Postfix relay is working correctly!
|
||||||
|
"
|
||||||
|
|
||||||
|
if docker exec postfix-relay sh -c "echo '$test_message' | mail -s 'Postfix Relay Test - $timestamp' $recipient" 2>&1; then
|
||||||
|
print_success "Test email sent to $recipient"
|
||||||
|
print_info "Check the mail queue and logs:"
|
||||||
|
echo ""
|
||||||
|
docker exec postfix-relay postqueue -p
|
||||||
|
else
|
||||||
|
print_error "Failed to send test email"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show logs
|
||||||
|
show_logs() {
|
||||||
|
print_header "Recent Logs"
|
||||||
|
docker logs --tail 50 postfix-relay
|
||||||
|
}
|
||||||
|
|
||||||
|
# Full test suite
|
||||||
|
run_full_test() {
|
||||||
|
print_header "Running Full Test Suite"
|
||||||
|
|
||||||
|
check_env
|
||||||
|
check_docker
|
||||||
|
check_container
|
||||||
|
check_postfix
|
||||||
|
check_network
|
||||||
|
check_config
|
||||||
|
check_queue
|
||||||
|
|
||||||
|
print_header "Test Summary"
|
||||||
|
print_success "All checks passed!"
|
||||||
|
print_info "Container is ready to relay emails"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
read -p "Do you want to send a test email? (y/n): " send_test
|
||||||
|
if [ "$send_test" = "y" ] || [ "$send_test" = "Y" ]; then
|
||||||
|
send_test_email
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main menu
|
||||||
|
show_menu() {
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}Postfix SMTP Relay Test Menu${NC}"
|
||||||
|
echo "================================"
|
||||||
|
echo "1) Run full test suite"
|
||||||
|
echo "2) Check environment"
|
||||||
|
echo "3) Check container status"
|
||||||
|
echo "4) Check Postfix configuration"
|
||||||
|
echo "5) Check mail queue"
|
||||||
|
echo "6) Send test email"
|
||||||
|
echo "7) Show logs"
|
||||||
|
echo "8) Exit"
|
||||||
|
echo ""
|
||||||
|
read -p "Select option: " option
|
||||||
|
|
||||||
|
case $option in
|
||||||
|
1) run_full_test ;;
|
||||||
|
2) check_env ;;
|
||||||
|
3) check_container && check_postfix ;;
|
||||||
|
4) check_config ;;
|
||||||
|
5) check_queue ;;
|
||||||
|
6) send_test_email ;;
|
||||||
|
7) show_logs ;;
|
||||||
|
8) exit 0 ;;
|
||||||
|
*) print_error "Invalid option"; show_menu ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
# No arguments, show menu
|
||||||
|
show_menu
|
||||||
|
else
|
||||||
|
case "$1" in
|
||||||
|
--full|-f)
|
||||||
|
run_full_test
|
||||||
|
;;
|
||||||
|
--email|-e)
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
send_test_email "$2"
|
||||||
|
else
|
||||||
|
send_test_email
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
--check|-c)
|
||||||
|
check_env
|
||||||
|
check_docker
|
||||||
|
check_container
|
||||||
|
check_postfix
|
||||||
|
check_config
|
||||||
|
;;
|
||||||
|
--logs|-l)
|
||||||
|
show_logs
|
||||||
|
;;
|
||||||
|
--queue|-q)
|
||||||
|
check_queue
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
echo "Postfix SMTP Relay Test Script"
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 [option] [arguments]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -f, --full Run full test suite"
|
||||||
|
echo " -c, --check Run configuration checks"
|
||||||
|
echo " -e, --email [address] Send test email"
|
||||||
|
echo " -q, --queue Check mail queue"
|
||||||
|
echo " -l, --logs Show recent logs"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 # Interactive menu"
|
||||||
|
echo " $0 --full # Run all tests"
|
||||||
|
echo " $0 --email user@example.com # Send test email"
|
||||||
|
echo " $0 --check # Check configuration"
|
||||||
|
echo ""
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Unknown option: $1"
|
||||||
|
echo "Use --help for usage information"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
Reference in new issue
Block a user