Adding the configuration change for multiple provider, Making the service run in foreground and adding test

This commit is contained in:
Ketan Patel committed 2025-10-30 16:58:53 -04:00
1 parent 85ab503afb
commit 4eaa4d91ea
10 files changed
+1639 -140

No files matched your search

+188
View File
@@ -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"
+200
View File
@@ -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
View File
@@ -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