Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:05:59 +08:00
commit 37120368e6
13 changed files with 5177 additions and 0 deletions

View File

@@ -0,0 +1,861 @@
#!/bin/bash
# mailhog_manager.sh - Comprehensive MailHog server management utility
# Usage: ./mailhog_manager.sh [COMMAND] [OPTIONS]
set -e
# Default configuration
DEFAULT_SMTP_PORT=1025
DEFAULT_UI_PORT=8025
DEFAULT_API_PORT=8025
DEFAULT_HOSTNAME="mailhog.local"
DEFAULT_STORAGE="memory"
PID_FILE="/tmp/mailhog.pid"
LOG_FILE="/tmp/mailhog.log"
CONFIG_FILE="$HOME/.mailhog_config"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Print colored output
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
print_header() {
echo -e "${CYAN}=== $1 ===${NC}"
}
# Show usage information
show_usage() {
cat << EOF
MailHog Server Manager
Usage: $0 COMMAND [OPTIONS]
COMMANDS:
start Start MailHog server
stop Stop MailHog server
restart Restart MailHog server
status Show MailHog server status
logs Show MailHog server logs
config Show current configuration
test Test MailHog functionality
cleanup Clean up MailHog data
install Install MailHog (if not installed)
update Update MailHog to latest version
START OPTIONS:
-p, --smtp-port PORT SMTP port (default: $DEFAULT_SMTP_PORT)
-u, --ui-port PORT UI/API port (default: $DEFAULT_UI_PORT)
-h, --hostname HOST Hostname (default: $DEFAULT_HOSTNAME)
-s, --storage TYPE Storage type: memory, mongodb, maildir (default: $DEFAULT_STORAGE)
--mongo-uri URI MongoDB connection URI (for MongoDB storage)
--mongo-db DB MongoDB database name (default: mailhog)
--mongo-coll COLL MongoDB collection name (default: messages)
--maildir-path PATH Maildir storage path
--auth-file FILE Authentication file path
--outgoing-smtp FILE Outgoing SMTP configuration file
--cors-origin ORIGIN CORS origin
--invite-jim Enable Jim network simulation
-d, --daemon Run in daemon mode
-v, --verbose Enable verbose logging
CONFIGURATION:
--save Save current configuration as default
--load Load saved configuration
--reset Reset configuration to defaults
TESTING OPTIONS:
--send-email Send test email
--check-connection Check SMTP connection
--check-api Check API connection
--cleanup-test Clean up test emails
EXAMPLES:
# Start MailHog with default settings
$0 start
# Start with custom ports and MongoDB storage
$0 start --smtp-port 1026 --ui-port 8026 --storage mongodb --mongo-uri mongodb://localhost:27017
# Start in daemon mode with authentication
$0 start --auth-file /path/to/auth.txt --daemon
# Check server status
$0 status
# Send test email
$0 test --send-email --to test@recipient.local
# View logs
$0 logs
# Save current configuration
$0 config --save
INSTALLATION:
# Install MailHog (Linux/macOS)
$0 install
# Update to latest version
$0 update
EOF
}
# Load configuration from file
load_config() {
if [[ -f "$CONFIG_FILE" ]]; then
print_info "Loading configuration from $CONFIG_FILE"
# Source the configuration file
source "$CONFIG_FILE"
fi
}
# Save current configuration
save_config() {
cat > "$CONFIG_FILE" << EOF
# MailHog Configuration
SMTP_PORT="$SMTP_PORT"
UI_PORT="$UI_PORT"
API_PORT="$API_PORT"
HOSTNAME="$HOSTNAME"
STORAGE="$STORAGE"
MONGO_URI="$MONGO_URI"
MONGO_DB="$MONGO_DB"
MONGO_COLL="$MONGO_COLL"
MAILDIR_PATH="$MAILDIR_PATH"
AUTH_FILE="$AUTH_FILE"
OUTGOING_SMTP="$OUTGOING_SMTP"
CORS_ORIGIN="$CORS_ORIGIN"
INVITE_JIM="$INVITE_JIM"
EOF
print_success "Configuration saved to $CONFIG_FILE"
}
# Reset configuration to defaults
reset_config() {
SMTP_PORT="$DEFAULT_SMTP_PORT"
UI_PORT="$DEFAULT_UI_PORT"
API_PORT="$DEFAULT_API_PORT"
HOSTNAME="$DEFAULT_HOSTNAME"
STORAGE="$DEFAULT_STORAGE"
MONGO_URI=""
MONGO_DB="mailhog"
MONGO_COLL="messages"
MAILDIR_PATH=""
AUTH_FILE=""
OUTGOING_SMTP=""
CORS_ORIGIN=""
INVITE_JIM=""
print_success "Configuration reset to defaults"
}
# Check if MailHog is installed
check_mailhog_installed() {
if command -v mailhog >/dev/null 2>&1; then
return 0
else
return 1
fi
}
# Install MailHog
install_mailhog() {
print_header "Installing MailHog"
if check_mailhog_installed; then
print_warning "MailHog is already installed"
return 0
fi
local os=$(uname -s | tr '[:upper:]' '[:lower:]')
local arch=$(uname -m)
# Determine architecture
case "$arch" in
x86_64)
arch="amd64"
;;
aarch64|arm64)
arch="arm64"
;;
armv7l)
arch="arm7"
;;
*)
print_error "Unsupported architecture: $arch"
return 1
;;
esac
# Get latest version
local latest_version=$(curl -s "https://api.github.com/repos/mailhog/MailHog/releases/latest" | grep -o '"tag_name": "[^"]*' | cut -d'"' -f2 | sed 's/v//')
if [[ -z "$latest_version" ]]; then
print_error "Failed to fetch latest MailHog version"
return 1
fi
local download_url="https://github.com/mailhog/MailHog/releases/download/v${latest_version}/MailHog_${os}_${arch}.zip"
print_info "Downloading MailHog v${latest_version} for ${os}/${arch}..."
# Download and extract
local temp_dir=$(mktemp -d)
cd "$temp_dir"
if curl -L -o mailhog.zip "$download_url"; then
unzip mailhog.zip
chmod +x MailHog
# Move to binary directory
if [[ -w "/usr/local/bin" ]]; then
sudo mv MailHog /usr/local/bin/
elif [[ -w "$HOME/.local/bin" ]]; then
mkdir -p "$HOME/.local/bin"
mv MailHog "$HOME/.local/bin/"
# Add to PATH if not already there
if ! echo "$PATH" | grep -q "$HOME/.local/bin"; then
echo 'export PATH="$PATH:$HOME/.local/bin"' >> "$HOME/.bashrc"
export PATH="$PATH:$HOME/.local/bin"
fi
else
print_error "No writable binary directory found. Please install manually."
cd /
rm -rf "$temp_dir"
return 1
fi
cd /
rm -rf "$temp_dir"
print_success "MailHog v${latest_version} installed successfully"
return 0
else
print_error "Failed to download MailHog"
cd /
rm -rf "$temp_dir"
return 1
fi
}
# Update MailHog
update_mailhog() {
print_header "Updating MailHog"
if ! check_mailhog_installed; then
print_warning "MailHog not installed. Installing..."
install_mailhog
return $?
fi
# Stop MailHog if running
if is_mailhog_running; then
stop_mailhog
fi
# Install latest version
install_mailhog
}
# Check if MailHog is running
is_mailhog_running() {
if [[ -f "$PID_FILE" ]]; then
local pid=$(cat "$PID_FILE")
if ps -p "$pid" > /dev/null 2>&1; then
return 0
else
# PID file exists but process is not running
rm -f "$PID_FILE"
return 1
fi
fi
# Check by looking for mailhog process
if pgrep -f "mailhog" > /dev/null; then
return 0
fi
return 1
}
# Build MailHog command with current configuration
build_mailhog_command() {
local cmd="mailhog"
# Basic configuration
cmd+=" -hostname $HOSTNAME"
cmd+=" -smtp-bind-addr 0.0.0.0:$SMTP_PORT"
cmd+=" -ui-bind-addr 0.0.0.0:$UI_PORT"
cmd+=" -api-bind-addr 0.0.0.0:$API_PORT"
# Storage configuration
case "$STORAGE" in
"mongodb")
if [[ -n "$MONGO_URI" ]]; then
cmd+=" -storage mongodb -mongo-uri $MONGO_URI"
else
cmd+=" -storage mongodb -mongo-uri 127.0.0.1:27017"
fi
if [[ -n "$MONGO_DB" ]]; then
cmd+=" -mongo-db $MONGO_DB"
fi
if [[ -n "$MONGO_COLL" ]]; then
cmd+=" -mongo-coll $MONGO_COLL"
fi
;;
"maildir")
if [[ -n "$MAILDIR_PATH" ]]; then
cmd+=" -storage maildir -maildir-path $MAILDIR_PATH"
else
cmd+=" -storage maildir -maildir-path ./maildir"
fi
;;
*)
cmd+=" -storage memory"
;;
esac
# Optional configurations
if [[ -n "$AUTH_FILE" ]]; then
cmd+=" -auth-file $AUTH_FILE"
fi
if [[ -n "$OUTGOING_SMTP" ]]; then
cmd+=" -outgoing-smtp $OUTGOING_SMTP"
fi
if [[ -n "$CORS_ORIGIN" ]]; then
cmd+=" -cors-origin \"$CORS_ORIGIN\""
fi
if [[ "$INVITE_JIM" == "true" ]]; then
cmd+=" -invite-jim"
fi
echo "$cmd"
}
# Start MailHog
start_mailhog() {
print_header "Starting MailHog"
if is_mailhog_running; then
print_warning "MailHog is already running"
return 0
fi
if ! check_mailhog_installed; then
print_error "MailHog is not installed. Run '$0 install' first."
return 1
fi
# Check if ports are available
if netstat -tlnp 2>/dev/null | grep -q ":$SMTP_PORT "; then
print_error "Port $SMTP_PORT is already in use"
return 1
fi
if netstat -tlnp 2>/dev/null | grep -q ":$UI_PORT "; then
print_error "Port $UI_PORT is already in use"
return 1
fi
local mailhog_cmd=$(build_mailhog_command)
print_info "Starting MailHog with the following command:"
print_info "$mailhog_cmd"
if [[ "$DAEMON_MODE" == true ]]; then
# Start in daemon mode
nohup $mailhog_cmd > "$LOG_FILE" 2>&1 &
local pid=$!
echo "$pid" > "$PID_FILE"
print_success "MailHog started in daemon mode (PID: $pid)"
print_info "Logs are being written to: $LOG_FILE"
else
# Start in foreground
$mailhog_cmd 2>&1 | tee "$LOG_FILE" &
local pid=$!
echo "$pid" > "$PID_FILE"
print_success "MailHog started (PID: $pid)"
fi
# Wait a moment and check if it started successfully
sleep 2
if is_mailhog_running; then
print_success "MailHog started successfully"
print_info "SMTP server: localhost:$SMTP_PORT"
print_info "Web UI: http://localhost:$UI_PORT"
print_info "API: http://localhost:$API_PORT/api/v1"
else
print_error "MailHog failed to start"
return 1
fi
}
# Stop MailHog
stop_mailhog() {
print_header "Stopping MailHog"
if ! is_mailhog_running; then
print_warning "MailHog is not running"
return 0
fi
local pid=""
if [[ -f "$PID_FILE" ]]; then
pid=$(cat "$PID_FILE")
else
# Try to find PID by process name
pid=$(pgrep -f "mailhog" | head -1)
fi
if [[ -n "$pid" ]]; then
print_info "Stopping MailHog (PID: $pid)"
kill "$pid"
# Wait for process to stop
local count=0
while ps -p "$pid" > /dev/null 2>&1 && [[ $count -lt 10 ]]; do
sleep 1
((count++))
done
# Force kill if still running
if ps -p "$pid" > /dev/null 2>&1; then
print_warning "Force killing MailHog process"
kill -9 "$pid"
fi
rm -f "$PID_FILE"
print_success "MailHog stopped"
else
print_warning "Could not find MailHog process to stop"
fi
}
# Restart MailHog
restart_mailhog() {
print_header "Restarting MailHog"
stop_mailhog
sleep 2
start_mailhog
}
# Show MailHog status
show_status() {
print_header "MailHog Status"
if is_mailhog_running; then
print_success "MailHog is running"
# Show process information
if [[ -f "$PID_FILE" ]]; then
local pid=$(cat "$PID_FILE")
print_info "PID: $pid"
print_info "Command: $(ps -p "$pid" -o cmd=)"
fi
# Show configuration
echo ""
print_info "Configuration:"
print_info " SMTP Port: $SMTP_PORT"
print_info " UI Port: $UI_PORT"
print_info " API Port: $API_PORT"
print_info " Hostname: $HOSTNAME"
print_info " Storage: $STORAGE"
# Test API connection
echo ""
print_info "Testing API connection..."
if curl -s --max-time 3 "http://localhost:$API_PORT/api/v1/status" > /dev/null 2>&1; then
print_success "API is accessible"
local messages=$(curl -s "http://localhost:$API_PORT/api/v1/messages" 2>/dev/null | jq -r '.total // 0' 2>/dev/null || echo "unknown")
print_info "Messages stored: $messages"
else
print_error "API is not accessible"
fi
# Show URLs
echo ""
print_info "Access URLs:"
print_info " Web UI: http://localhost:$UI_PORT"
print_info " API: http://localhost:$API_PORT/api/v1"
print_info " SMTP: localhost:$SMTP_PORT"
else
print_error "MailHog is not running"
fi
}
# Show logs
show_logs() {
print_header "MailHog Logs"
if [[ -f "$LOG_FILE" ]]; then
tail -f "$LOG_FILE"
else
print_warning "Log file not found: $LOG_FILE"
fi
}
# Show configuration
show_config() {
print_header "Current Configuration"
echo "SMTP Port: $SMTP_PORT"
echo "UI Port: $UI_PORT"
echo "API Port: $API_PORT"
echo "Hostname: $HOSTNAME"
echo "Storage: $STORAGE"
if [[ "$STORAGE" == "mongodb" ]]; then
echo "MongoDB URI: ${MONGO_URI:-"127.0.0.1:27017"}"
echo "MongoDB DB: $MONGO_DB"
echo "MongoDB Collection: $MONGO_COLL"
fi
if [[ "$STORAGE" == "maildir" ]]; then
echo "Maildir Path: ${MAILDIR_PATH:-"./maildir"}"
fi
echo "Auth File: ${AUTH_FILE:-"none"}"
echo "Outgoing SMTP: ${OUTGOING_SMTP:-"none"}"
echo "CORS Origin: ${CORS_ORIGIN:-"none"}"
echo "Jim Simulation: ${INVITE_JIM:-"false"}"
echo ""
echo "MailHog Command:"
echo "$(build_mailhog_command)"
}
# Test MailHog functionality
test_mailhog() {
print_header "Testing MailHog"
if ! is_mailhog_running; then
print_error "MailHog is not running"
return 1
fi
# Test API connection
if [[ "$CHECK_API" == true ]]; then
print_info "Testing API connection..."
local response=$(curl -s "http://localhost:$API_PORT/api/v1/status" 2>/dev/null)
if [[ $? -eq 0 ]]; then
print_success "API connection successful"
echo "$response" | jq . 2>/dev/null || echo "$response"
else
print_error "API connection failed"
fi
fi
# Test SMTP connection
if [[ "$CHECK_CONNECTION" == true ]]; then
print_info "Testing SMTP connection..."
if echo "" | nc -w 3 localhost "$SMTP_PORT" 2>/dev/null | grep -q "220"; then
print_success "SMTP connection successful"
else
print_error "SMTP connection failed"
fi
fi
# Send test email
if [[ "$SEND_EMAIL" == true ]]; then
print_info "Sending test email..."
local test_to="${TEST_TO:-test@recipient.local}"
local test_from="${TEST_FROM:-test@sender.local}"
local test_subject="MailHog Test Email $(date +%s)"
local test_body="This is a test email sent at $(date)"
# Send email using netcat
(
echo "EHLO localhost"
echo "MAIL FROM:<$test_from>"
echo "RCPT TO:<$test_to>"
echo "DATA"
echo "From: $test_from"
echo "To: $test_to"
echo "Subject: $test_subject"
echo "Date: $(date -R)"
echo ""
echo "$test_body"
echo "."
echo "QUIT"
) | nc localhost "$SMTP_PORT" 2>/dev/null
if [[ $? -eq 0 ]]; then
print_success "Test email sent to $test_to"
# Wait and check if received
sleep 2
local messages=$(curl -s "http://localhost:$API_PORT/api/v1/messages" 2>/dev/null | jq -r '.total // 0' 2>/dev/null)
if [[ "$messages" -gt 0 ]]; then
print_success "Test email received by MailHog ($messages total messages)"
else
print_warning "Test email not found in MailHog (may need more time)"
fi
else
print_error "Failed to send test email"
fi
fi
# Clean up test emails
if [[ "$CLEANUP_TEST" == true ]]; then
print_info "Cleaning up test emails..."
local response=$(curl -s -X DELETE "http://localhost:$API_PORT/api/v1/messages" 2>/dev/null)
if [[ $? -eq 0 ]]; then
print_success "Test emails cleaned up"
else
print_warning "Failed to clean up test emails"
fi
fi
}
# Clean up MailHog data
cleanup_mailhog() {
print_header "Cleaning up MailHog"
if is_mailhog_running; then
print_info "Clearing all messages..."
local response=$(curl -s -X DELETE "http://localhost:$API_PORT/api/v1/messages" 2>/dev/null)
if [[ $? -eq 0 ]]; then
print_success "All messages cleared"
else
print_warning "Failed to clear messages"
fi
else
print_warning "MailHog is not running"
fi
# Clean up temporary files
print_info "Cleaning up temporary files..."
rm -f "$PID_FILE" "$LOG_FILE"
# Optional: Clean up maildir if used
if [[ "$STORAGE" == "maildir" ]] && [[ -n "$MAILDIR_PATH" ]]; then
if [[ -d "$MAILDIR_PATH" ]]; then
print_info "Cleaning up Maildir storage..."
rm -rf "$MAILDIR_PATH"/{cur,new,tmp}/*
print_success "Maildir storage cleaned"
fi
fi
print_success "Cleanup completed"
}
# Main function
main() {
# Load default configuration
load_config
# Set defaults if not loaded
SMTP_PORT="${SMTP_PORT:-$DEFAULT_SMTP_PORT}"
UI_PORT="${UI_PORT:-$DEFAULT_UI_PORT}"
API_PORT="${API_PORT:-$DEFAULT_API_PORT}"
HOSTNAME="${HOSTNAME:-$DEFAULT_HOSTNAME}"
STORAGE="${STORAGE:-$DEFAULT_STORAGE}"
MONGO_DB="${MONGO_DB:-mailhog}"
MONGO_COLL="${MONGO_COLL:-messages}"
DAEMON_MODE=false
# Parse command line arguments
case "${1:-}" in
"start")
shift
while [[ $# -gt 0 ]]; do
case $1 in
-p|--smtp-port)
SMTP_PORT="$2"
shift 2
;;
-u|--ui-port)
UI_PORT="$2"
API_PORT="$2"
shift 2
;;
-h|--hostname)
HOSTNAME="$2"
shift 2
;;
-s|--storage)
STORAGE="$2"
shift 2
;;
--mongo-uri)
MONGO_URI="$2"
shift 2
;;
--mongo-db)
MONGO_DB="$2"
shift 2
;;
--mongo-coll)
MONGO_COLL="$2"
shift 2
;;
--maildir-path)
MAILDIR_PATH="$2"
shift 2
;;
--auth-file)
AUTH_FILE="$2"
shift 2
;;
--outgoing-smtp)
OUTGOING_SMTP="$2"
shift 2
;;
--cors-origin)
CORS_ORIGIN="$2"
shift 2
;;
--invite-jim)
INVITE_JIM="true"
shift
;;
-d|--daemon)
DAEMON_MODE=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
--save)
save_config
exit 0
;;
*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
start_mailhog
;;
"stop")
stop_mailhog
;;
"restart")
restart_mailhog
;;
"status")
show_status
;;
"logs")
show_logs
;;
"config")
case "${2:-}" in
"--save")
save_config
;;
"--load")
load_config
print_success "Configuration loaded"
;;
"--reset")
reset_config
;;
*)
show_config
;;
esac
;;
"test")
shift
while [[ $# -gt 0 ]]; do
case $1 in
--send-email)
SEND_EMAIL=true
shift
;;
--check-connection)
CHECK_CONNECTION=true
shift
;;
--check-api)
CHECK_API=true
shift
;;
--cleanup-test)
CLEANUP_TEST=true
shift
;;
--to)
TEST_TO="$2"
shift 2
;;
--from)
TEST_FROM="$2"
shift 2
;;
*)
print_error "Unknown test option: $1"
show_usage
exit 1
;;
esac
done
# If no specific test options, run all tests
if [[ -z "$SEND_EMAIL" && -z "$CHECK_CONNECTION" && -z "$CHECK_API" && -z "$CLEANUP_TEST" ]]; then
SEND_EMAIL=true
CHECK_CONNECTION=true
CHECK_API=true
CLEANUP_TEST=true
fi
test_mailhog
;;
"cleanup")
cleanup_mailhog
;;
"install")
install_mailhog
;;
"update")
update_mailhog
;;
"help"|"-h"|"--help")
show_usage
;;
*)
print_error "Unknown command: ${1:-}"
show_usage
exit 1
;;
esac
}
# Run main function
main "$@"

View File

@@ -0,0 +1,493 @@
#!/bin/bash
# send_test_email.sh - Send test emails via SMTP to MailHog
# Usage: ./send_test_email.sh [OPTIONS]
set -e
# Default values
SMTP_HOST="localhost"
SMTP_PORT="1025"
TO="test@recipient.local"
FROM="test@sender.local"
SUBJECT="Test Email from MailHog Skill"
BODY="This is a test email sent via the MailHog skill script."
HTML=false
ATTACHMENT=""
VERBOSE=false
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Print colored output
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Show usage information
show_usage() {
cat << EOF
Send Test Email Script
Usage: $0 [OPTIONS]
OPTIONS:
-h, --help Show this help message
-t, --to EMAIL Recipient email address (default: test@recipient.local)
-f, --from EMAIL Sender email address (default: test@sender.local)
-s, --subject SUBJECT Email subject (default: "Test Email from MailHog Skill")
-b, --body TEXT Email body text (default: simple test message)
--html Send as HTML email
--attachment FILE Attach file to email
--smtp-host HOST SMTP server host (default: localhost)
--smtp-port PORT SMTP server port (default: 1025)
-v, --verbose Enable verbose output
--template TEMPLATE Use predefined template (welcome, notification, reset)
--multiple COUNT Send multiple emails (for testing)
TEMPLATES:
welcome - Welcome email template
notification - Notification email template
reset - Password reset email template
bulk - Bulk email test template
EXAMPLES:
# Send simple test email
$0 --to user@test.local --subject "Welcome!"
# Send HTML email with template
$0 --html --template welcome --to newuser@test.local
# Send multiple emails for load testing
$0 --multiple 100 --subject "Load Test"
# Send email with attachment
$0 --attachment ./test.pdf --to recipient@test.local
EOF
}
# Email templates
get_template_content() {
local template="$1"
local to="$2"
case "$template" in
"welcome")
echo "<h1>Welcome to Our Service!</h1>
<p>Hello $to,</p>
<p>Thank you for signing up for our service. We're excited to have you on board!</p>
<p>Here's what you can do next:</p>
<ul>
<li>Complete your profile</li>
<li>Explore our features</li>
<li>Connect with other users</li>
</ul>
<p>Best regards,<br>The Team</p>"
echo "Welcome to Our Service!"
;;
"notification")
echo "<h2>Important Notification</h1>
<p>Hello $to,</p>
<p>You have an important notification that requires your attention.</p>
<div style='background-color: #f8f9fa; padding: 15px; border-left: 4px solid #007bff;'>
<strong>Action Required:</strong> Please review your account settings.
</div>
<p>Thank you for your prompt attention to this matter.</p>"
echo "Important Notification"
;;
"reset")
echo "<h1>Password Reset Request</h1>
<p>Hello $to,</p>
<p>You requested a password reset for your account. Click the link below to reset your password:</p>
<p><a href='https://example.com/reset?token=abc123' style='background-color: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;'>Reset Password</a></p>
<p>If you didn't request this reset, please ignore this email. The link will expire in 1 hour.</p>
<p>Best regards,<br>Support Team</p>"
echo "Password Reset Request"
;;
"bulk")
echo "<h2>Bulk Communication</h1>
<p>This is a test email for bulk communication testing.</p>
<p>Message ID: $(date +%s)</p>
<p>Timestamp: $(date)</p>"
echo "Bulk Communication Test"
;;
*)
print_error "Unknown template: $template"
exit 1
;;
esac
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_usage
exit 0
;;
-t|--to)
TO="$2"
shift 2
;;
-f|--from)
FROM="$2"
shift 2
;;
-s|--subject)
SUBJECT="$2"
shift 2
;;
-b|--body)
BODY="$2"
shift 2
;;
--html)
HTML=true
shift
;;
--attachment)
ATTACHMENT="$2"
if [[ ! -f "$ATTACHMENT" ]]; then
print_error "Attachment file not found: $ATTACHMENT"
exit 1
fi
shift 2
;;
--smtp-host)
SMTP_HOST="$2"
shift 2
;;
--smtp-port)
SMTP_PORT="$2"
shift 2
;;
-v|--verbose)
VERBOSE=true
shift
;;
--template)
TEMPLATE="$2"
shift 2
;;
--multiple)
MULTIPLE="$2"
shift 2
;;
*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Check if netcat is available
check_dependencies() {
local missing_deps=()
if ! command -v nc >/dev/null 2>&1 && ! command -v telnet >/dev/null 2>&1; then
missing_deps+=("nc or telnet")
fi
if [[ ${#missing_deps[@]} -gt 0 ]]; then
print_error "Missing required dependencies: ${missing_deps[*]}"
print_info "Install missing dependencies and try again."
exit 1
fi
}
# Test SMTP connection
test_smtp_connection() {
print_info "Testing SMTP connection to $SMTP_HOST:$SMTP_PORT..."
if command -v nc >/dev/null 2>&1; then
if echo "" | nc -w 5 "$SMTP_HOST" "$SMTP_PORT" >/dev/null 2>&1; then
print_success "SMTP connection successful"
return 0
else
print_error "Failed to connect to SMTP server"
return 1
fi
elif command -v telnet >/dev/null 2>&1; then
timeout 5 telnet "$SMTP_HOST" "$SMTP_PORT" </dev/null >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
print_success "SMTP connection successful"
return 0
else
print_error "Failed to connect to SMTP server"
return 1
fi
fi
}
# Create temporary file for email
create_email_file() {
local temp_file=$(mktemp)
local boundary="MAILHOG-$(date +%s%N)"
cat << EOF > "$temp_file"
From: $FROM
To: $TO
Subject: $SUBJECT
Date: $(date -R)
MIME-Version: 1.0
EOF
if [[ -n "$ATTACHMENT" ]]; then
echo "Content-Type: multipart/mixed; boundary=\"$boundary\"" >> "$temp_file"
echo "" >> "$temp_file"
echo "--$boundary" >> "$temp_file"
if [[ "$HTML" == true ]]; then
echo "Content-Type: text/html; charset=UTF-8" >> "$temp_file"
echo "Content-Transfer-Encoding: 7bit" >> "$temp_file"
else
echo "Content-Type: text/plain; charset=UTF-8" >> "$temp_file"
echo "Content-Transfer-Encoding: 7bit" >> "$temp_file"
fi
echo "" >> "$temp_file"
echo "$BODY" >> "$temp_file"
echo "" >> "$temp_file"
echo "--$boundary" >> "$temp_file"
# Add attachment
local attachment_name=$(basename "$ATTACHMENT")
echo "Content-Type: application/octet-stream" >> "$temp_file"
echo "Content-Transfer-Encoding: base64" >> "$temp_file"
echo "Content-Disposition: attachment; filename=\"$attachment_name\"" >> "$temp_file"
echo "" >> "$temp_file"
base64 "$ATTACHMENT" >> "$temp_file"
echo "" >> "$temp_file"
echo "--$boundary--" >> "$temp_file"
else
if [[ "$HTML" == true ]]; then
echo "Content-Type: text/html; charset=UTF-8" >> "$temp_file"
echo "Content-Transfer-Encoding: 7bit" >> "$temp_file"
else
echo "Content-Type: text/plain; charset=UTF-8" >> "$temp_file"
fi
echo "" >> "$temp_file"
echo "$BODY" >> "$temp_file"
fi
echo "$temp_file"
}
# Send email using SMTP
send_email_smtp() {
local email_file="$1"
if [[ "$VERBOSE" == true ]]; then
print_info "Sending email with the following content:"
cat "$email_file"
echo ""
fi
# Connect to SMTP and send email
(
echo "EHLO mailhog-test.local"
echo "MAIL FROM:<$FROM>"
echo "RCPT TO:<$TO>"
echo "DATA"
cat "$email_file"
echo "."
echo "QUIT"
) | nc "$SMTP_HOST" "$SMTP_PORT" 2>/dev/null
if [[ $? -eq 0 ]]; then
print_success "Email sent successfully"
return 0
else
print_error "Failed to send email"
return 1
fi
}
# Send email using Python if available
send_email_python() {
local email_file="$1"
if command -v python3 >/dev/null 2>&1; then
python3 << EOF
import smtplib
import ssl
from email import message_from_file
try:
with open('$email_file', 'r') as f:
msg = message_from_file(f)
# Convert to string for sending
email_string = msg.as_string()
# Connect to SMTP server
server = smtplib.SMTP('$SMTP_HOST', $SMTP_PORT)
server.set_debuglevel(1 if '$VERBOSE' == 'true' else 0)
# Send email
server.sendmail('$FROM', ['$TO'], email_string)
server.quit()
print("Email sent successfully via Python")
except Exception as e:
print(f"Failed to send email via Python: {e}")
exit(1)
EOF
return $?
else
return 1
fi
}
# Send multiple emails for testing
send_multiple_emails() {
local count="$1"
local success_count=0
local failed_count=0
print_info "Sending $count emails..."
for ((i=1; i<=count; i++)); do
local temp_subject="$SUBJECT - #$i"
local temp_body="This is test email #$i\n\nSent at: $(date)"
if [[ "$HTML" == true ]]; then
temp_body="<h2>This is test email #$i</h2><p>Sent at: $(date)</p>"
fi
local temp_file=$(mktemp)
cat << EOF > "$temp_file"
From: $FROM
To: $TO
Subject: $temp_subject
Date: $(date -R)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
$temp_body
EOF
if send_email_smtp "$temp_file"; then
((success_count++))
else
((failed_count++))
fi
rm -f "$temp_file"
# Progress indicator
if [[ $((i % 10)) -eq 0 ]]; then
print_info "Sent $i/$count emails..."
fi
# Small delay to avoid overwhelming the server
sleep 0.1
done
print_success "Email sending complete: $success_count successful, $failed_count failed"
}
# Check MailHog for the sent email
verify_email_received() {
local max_attempts=10
local attempt=1
print_info "Verifying email was received by MailHog..."
while [[ $attempt -le $max_attempts ]]; do
local response=$(curl -s "http://localhost:8025/api/v1/messages?limit=1" 2>/dev/null)
if [[ $? -eq 0 ]] && echo "$response" | grep -q "\"total\":1"; then
print_success "Email verified in MailHog"
if [[ "$VERBOSE" == true ]]; then
echo "$response" | jq '.'
fi
return 0
fi
sleep 1
((attempt++))
done
print_warning "Email not found in MailHog after verification attempts"
return 1
}
# Main execution
main() {
print_info "MailHog Test Email Sender"
# Check dependencies
check_dependencies
# Apply template if specified
if [[ -n "$TEMPLATE" ]]; then
if [[ "$VERBOSE" == true ]]; then
print_info "Using template: $TEMPLATE"
fi
local template_result=$(get_template_content "$TEMPLATE" "$TO")
BODY=$(echo "$template_result" | sed -n '1p')
SUBJECT=$(echo "$template_result" | sed -n '2p')
HTML=true
fi
# Test SMTP connection
test_smtp_connection
# Send multiple emails if requested
if [[ -n "$MULTIPLE" ]]; then
send_multiple_emails "$MULTIPLE"
exit 0
fi
# Create email file
local email_file=$(create_email_file)
# Send email
print_info "Sending email to $TO from $FROM via $SMTP_HOST:$SMTP_PORT..."
if ! send_email_smtp "$email_file"; then
# Fallback to Python if netcat fails
if send_email_python "$email_file"; then
print_success "Email sent successfully via Python fallback"
else
print_error "All email sending methods failed"
rm -f "$email_file"
exit 1
fi
fi
# Clean up
rm -f "$email_file"
# Verify email was received (only if running on same host as MailHog)
if [[ "$SMTP_HOST" == "localhost" ]] || [[ "$SMTP_HOST" == "127.0.0.1" ]]; then
verify_email_received
fi
print_success "Test email sending completed successfully"
}
# Run main function
main "$@"

View File

@@ -0,0 +1,855 @@
#!/bin/bash
# test_email_workflow.sh - Automated email testing workflow
# Usage: ./test_email_workflow.sh [OPTIONS]
set -e
# Default values
MAILHOG_URL="http://localhost:8025"
SMTP_HOST="localhost"
SMTP_PORT="1025"
CONFIG_FILE=""
TEST_SCENARIO="basic"
CLEANUP=true
VERBOSE=false
TIMEOUT=30
OUTPUT_FORMAT="text"
REPORT_FILE="email_test_report.txt"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Global variables
TOTAL_TESTS=0
PASSED_TESTS=0
FAILED_TESTS=0
TEST_RESULTS=()
# Print colored output
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
[[ "$VERBOSE" == true ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1" >> "$REPORT_FILE"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
[[ "$VERBOSE" == true ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS: $1" >> "$REPORT_FILE"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
[[ "$VERBOSE" == true ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARNING: $1" >> "$REPORT_FILE"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
[[ "$VERBOSE" == true ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >> "$REPORT_FILE"
}
print_test() {
echo -e "${CYAN}[TEST]${NC} $1"
[[ "$VERBOSE" == true ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] TEST: $1" >> "$REPORT_FILE"
}
# Show usage information
show_usage() {
cat << EOF
Automated Email Testing Workflow
Usage: $0 [OPTIONS]
OPTIONS:
-h, --help Show this help message
-c, --config FILE Load test configuration from file
-s, --scenario SCENARIO Test scenario to run (default: basic)
--url URL MailHog API URL (default: http://localhost:8025)
--smtp-host HOST SMTP server host (default: localhost)
--smtp-port PORT SMTP server port (default: 1025)
-t, --timeout SECONDS Timeout for each test (default: 30)
-v, --verbose Enable verbose output
--no-cleanup Don't clean up test emails after testing
--output FORMAT Report format: text, json, csv (default: text)
--report-file FILE Save report to file (default: email_test_report.txt)
TEST SCENARIOS:
basic - Basic email sending and receiving tests
html - HTML email formatting tests
attachments - Email attachment tests
bulk - Bulk email sending tests
performance - Performance and load tests
integration - Integration testing with different configurations
CONFIGURATION FILE FORMAT (JSON):
{
"tests": [
{
"name": "Test Name",
"type": "send|receive|search",
"to": "recipient@test.local",
"from": "sender@test.local",
"subject": "Test Subject",
"body": "Test body",
"html": false,
"expected_count": 1,
"timeout": 30
}
]
}
EXAMPLES:
# Run basic email tests
$0 --scenario basic
# Run HTML email tests with verbose output
$0 --scenario html --verbose
# Run tests with custom configuration
$0 --config test_config.json --timeout 60
# Run performance tests and save JSON report
$0 --scenario performance --output json --report-file perf_results.json
EOF
}
# Initialize test environment
init_test_environment() {
print_info "Initializing email test environment..."
# Initialize report file
if [[ "$VERBOSE" == true ]]; then
echo "Email Test Report - $(date)" > "$REPORT_FILE"
echo "==============================" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
fi
# Check if MailHog is accessible
check_mailhog_connection
# Clear existing messages if cleanup is enabled
if [[ "$CLEANUP" == true ]]; then
clear_mailhog_messages
fi
# Check SMTP connection
check_smtp_connection
print_success "Test environment initialized successfully"
}
# Check MailHog connection
check_mailhog_connection() {
print_test "Checking MailHog API connection..."
local response=$(curl -s --max-time 5 "$MAILHOG_URL/api/v1/status" 2>/dev/null)
if [[ $? -eq 0 ]] && echo "$response" | grep -q "messages"; then
print_success "MailHog API is accessible"
return 0
else
print_error "Cannot connect to MailHog API at $MAILHOG_URL"
return 1
fi
}
# Check SMTP connection
check_smtp_connection() {
print_test "Checking SMTP connection to $SMTP_HOST:$SMTP_PORT..."
if command -v nc >/dev/null 2>&1; then
if echo "" | nc -w 5 "$SMTP_HOST" "$SMTP_PORT" >/dev/null 2>&1; then
print_success "SMTP connection successful"
return 0
fi
elif command -v telnet >/dev/null 2>&1; then
timeout 5 telnet "$SMTP_HOST" "$SMTP_PORT" </dev/null >/dev/null 2>&1
if [[ $? -eq 0 || $? -eq 124 ]]; then
print_success "SMTP connection successful"
return 0
fi
fi
print_error "Failed to connect to SMTP server"
return 1
}
# Clear all MailHog messages
clear_mailhog_messages() {
print_test "Clearing existing MailHog messages..."
local response=$(curl -s -X DELETE "$MAILHOG_URL/api/v1/messages" 2>/dev/null)
if [[ $? -eq 0 ]]; then
print_success "MailHog messages cleared"
else
print_warning "Failed to clear MailHog messages"
fi
}
# Send test email
send_test_email() {
local to="$1"
local from="$2"
local subject="$3"
local body="$4"
local html="${5:-false}"
print_test "Sending test email to $to..."
# Create email content
local email_content="From: $from
To: $to
Subject: $subject
Date: $(date -R)
MIME-Version: 1.0"
if [[ "$html" == true ]]; then
email_content="$email_content
Content-Type: text/html; charset=UTF-8
$body"
else
email_content="$email_content
Content-Type: text/plain; charset=UTF-8
$body"
fi
# Send email via SMTP
(
echo "EHLO mailhog-test.local"
echo "MAIL FROM:<$from>"
echo "RCPT TO:<$to>"
echo "DATA"
echo "$email_content"
echo "."
echo "QUIT"
) | nc "$SMTP_HOST" "$SMTP_PORT" 2>/dev/null
return $?
}
# Wait for email to be received
wait_for_email() {
local to="$1"
local subject="$2"
local timeout="$3"
local start_time=$(date +%s)
local end_time=$((start_time + timeout))
print_test "Waiting for email to be received (timeout: ${timeout}s)..."
while [[ $(date +%s) -lt $end_time ]]; do
local response=$(curl -s "$MAILHOG_URL/api/v1/messages" 2>/dev/null)
if [[ $? -eq 0 ]]; then
local message_count=$(echo "$response" | jq -r '.total // 0' 2>/dev/null)
if [[ "$message_count" -gt 0 ]]; then
# Search for specific email
local search_response=$(curl -s -X POST "$MAILHOG_URL/api/v1/search" \
-H "Content-Type: application/json" \
-d "{\"query\":\"to:$to subject:$subject\"}" 2>/dev/null)
if [[ $? -eq 0 ]]; then
local found_count=$(echo "$search_response" | jq -r '.total // 0' 2>/dev/null)
if [[ "$found_count" -gt 0 ]]; then
print_success "Email received and found"
return 0
fi
fi
# If search fails, check if any new email was received
if [[ "$message_count" -gt 0 ]]; then
print_success "Email received (search failed, but count > 0)"
return 0
fi
fi
fi
sleep 1
done
print_error "Email not received within timeout period"
return 1
}
# Run a single test
run_test() {
local test_name="$1"
local test_type="$2"
shift 2
local test_params=("$@")
print_test "Running test: $test_name"
((TOTAL_TESTS++))
case "$test_type" in
"send")
run_send_test "$test_name" "${test_params[@]}"
;;
"receive")
run_receive_test "$test_name" "${test_params[@]}"
;;
"search")
run_search_test "$test_name" "${test_params[@]}"
;;
"bulk")
run_bulk_test "$test_name" "${test_params[@]}"
;;
*)
print_error "Unknown test type: $test_type"
record_test_result "$test_name" "FAILED" "Unknown test type"
;;
esac
}
# Run send email test
run_send_test() {
local test_name="$1"
local to="$2"
local from="$3"
local subject="$4"
local body="$5"
local html="${6:-false}"
local timeout="${7:-30}"
print_test "Sending email test: $test_name"
# Send email
if send_test_email "$to" "$from" "$subject" "$body" "$html"; then
# Wait for email to be received
if wait_for_email "$to" "$subject" "$timeout"; then
print_success "Test passed: $test_name"
record_test_result "$test_name" "PASSED" "Email sent and received successfully"
((PASSED_TESTS++))
else
print_error "Test failed: $test_name - Email not received"
record_test_result "$test_name" "FAILED" "Email sent but not received"
((FAILED_TESTS++))
fi
else
print_error "Test failed: $test_name - Email sending failed"
record_test_result "$test_name" "FAILED" "Email sending failed"
((FAILED_TESTS++))
fi
}
# Run receive test
run_receive_test() {
local test_name="$1"
local timeout="$2"
print_test "Receive test: $test_name"
# Send a test email first
local test_email="test-$(date +%s)@receiver.local"
if send_test_email "$test_email" "sender@test.local" "Receive Test" "Test email for receive test"; then
if wait_for_email "$test_email" "Receive Test" "$timeout"; then
print_success "Test passed: $test_name"
record_test_result "$test_name" "PASSED" "Email received successfully"
((PASSED_TESTS++))
else
print_error "Test failed: $test_name - Email not received"
record_test_result "$test_name" "FAILED" "Email not received within timeout"
((FAILED_TESTS++))
fi
else
print_error "Test failed: $test_name - Test email sending failed"
record_test_result "$test_name" "FAILED" "Test email sending failed"
((FAILED_TESTS++))
fi
}
# Run search test
run_search_test() {
local test_name="$1"
local query="$2"
local expected_count="$3"
print_test "Search test: $test_name"
# Send a test email first
local test_email="search-test-$(date +%s)@search.local"
if send_test_email "$test_email" "sender@test.local" "Search Test" "Test email for search test"; then
sleep 2 # Wait for email to be indexed
# Search for the email
local search_response=$(curl -s -X POST "$MAILHOG_URL/api/v1/search" \
-H "Content-Type: application/json" \
-d "{\"query\":\"$query\"}" 2>/dev/null)
if [[ $? -eq 0 ]]; then
local found_count=$(echo "$search_response" | jq -r '.total // 0' 2>/dev/null)
if [[ "$found_count" -eq "$expected_count" ]]; then
print_success "Test passed: $test_name - Found $found_count emails"
record_test_result "$test_name" "PASSED" "Found expected $expected_count emails"
((PASSED_TESTS++))
else
print_error "Test failed: $test_name - Expected $expected_count, found $found_count"
record_test_result "$test_name" "FAILED" "Expected $expected_count emails, found $found_count"
((FAILED_TESTS++))
fi
else
print_error "Test failed: $test_name - Search request failed"
record_test_result "$test_name" "FAILED" "Search request failed"
((FAILED_TESTS++))
fi
else
print_error "Test failed: $test_name - Test email sending failed"
record_test_result "$test_name" "FAILED" "Test email sending failed"
((FAILED_TESTS++))
fi
}
# Run bulk test
run_bulk_test() {
local test_name="$1"
local email_count="$2"
local timeout="$3"
print_test "Bulk test: $test_name - Sending $email_count emails"
local sent_count=0
local start_time=$(date +%s)
for ((i=1; i<=email_count; i++)); do
local test_email="bulk-$i-$(date +%s)@bulk.local"
if send_test_email "$test_email" "bulk@sender.local" "Bulk Test #$i" "Bulk test email #$i"; then
((sent_count++))
fi
# Small delay to avoid overwhelming
sleep 0.1
done
local send_time=$(($(date +%s) - start_time))
# Wait for all emails to be received
sleep "$timeout"
# Check total message count
local response=$(curl -s "$MAILHOG_URL/api/v1/messages" 2>/dev/null)
local received_count=0
if [[ $? -eq 0 ]]; then
received_count=$(echo "$response" | jq -r '.total // 0' 2>/dev/null)
fi
if [[ "$sent_count" -eq "$email_count" && "$received_count" -ge "$email_count" ]]; then
print_success "Test passed: $test_name - Sent $sent_count/$email_count, Received $received_count"
record_test_result "$test_name" "PASSED" "Bulk test: Sent $sent_count/$email_count emails in ${send_time}s"
((PASSED_TESTS++))
else
print_error "Test failed: $test_name - Sent $sent_count/$email_count, Received $received_count"
record_test_result "$test_name" "FAILED" "Bulk test: Expected $email_count, sent $sent_count, received $received_count"
((FAILED_TESTS++))
fi
}
# Record test result
record_test_result() {
local test_name="$1"
local result="$2"
local details="$3"
TEST_RESULTS+=("{\"name\":\"$test_name\",\"result\":\"$result\",\"details\":\"$details\"}")
}
# Run predefined test scenarios
run_basic_scenario() {
print_info "Running basic email tests..."
# Test 1: Simple text email
run_test "Simple Text Email" "send" \
"basic-test@test.local" \
"sender@test.local" \
"Basic Test Email" \
"This is a basic test email from the email testing workflow." \
false \
15
# Test 2: Different sender and recipient
run_test "Different Sender/Recipient" "send" \
"recipient1@test.local" \
"sender1@test.local" \
"Different Addresses Test" \
"Testing different sender and recipient addresses." \
false \
15
# Test 3: Special characters in subject
run_test "Special Characters Subject" "send" \
"special@test.local" \
"sender@test.local" \
"Subject with Special chars: àáâãäåæçèéêë" \
"Testing special characters in email subject line." \
false \
15
}
run_html_scenario() {
print_info "Running HTML email tests..."
# Test 1: Basic HTML email
run_test "Basic HTML Email" "send" \
"html@test.local" \
"sender@test.local" \
"HTML Test Email" \
"<h1>HTML Test</h1><p>This is an <strong>HTML</strong> email test.</p><ul><li>Item 1</li><li>Item 2</li></ul>" \
true \
15
# Test 2: HTML with CSS styling
run_test "HTML with CSS" "send" \
"html-css@test.local" \
"sender@test.local" \
"HTML + CSS Test" \
"<html><head><style>body{font-family:Arial,sans-serif} .highlight{background-color:yellow}</style></head><body><h1 class='highlight'>Styled HTML</h1><p>This email includes <span class='highlight'>CSS styling</span>.</p></body></html>" \
true \
15
# Test 3: HTML with images
run_test "HTML with Images" "send" \
"html-img@test.local" \
"sender@test.local" \
"HTML Image Test" \
"<h1>Image Test</h1><p>This email includes an embedded image:</p><img src='cid:test-image' alt='Test Image'><p>If you see an image placeholder, HTML parsing is working.</p>" \
true \
15
}
run_attachments_scenario() {
print_info "Running attachment tests..."
# Note: This is a simplified test. Real attachment testing would require multipart MIME construction
print_warning "Attachment tests require more complex MIME construction. This is a placeholder test."
run_test "Simple Attachment Test" "send" \
"attachment@test.local" \
"sender@test.local" \
"Attachment Test" \
"This test would normally include an attachment, but requires more complex MIME construction." \
false \
15
}
run_bulk_scenario() {
print_info "Running bulk email tests..."
# Test sending multiple emails
run_test "Bulk Send Test" "bulk" 10 30
# Test with more emails
run_test "Bulk Send Large Test" "bulk" 50 60
}
run_performance_scenario() {
print_info "Running performance tests..."
# Test performance with larger volume
run_test "Performance Test" "bulk" 100 120
# Test with timeout constraints
run_test "Quick Response Test" "send" \
"perf@test.local" \
"sender@test.local" \
"Performance Test" \
"Quick performance test email." \
false \
5
}
run_integration_scenario() {
print_info "Running integration tests..."
# Test with various timeouts
run_test "Long Timeout Test" "send" \
"integration@test.local" \
"sender@test.local" \
"Integration Test" \
"Integration test with extended timeout." \
false \
60
# Test search functionality
run_test "Email Search Test" "search" \
"search-test@test.local" \
1
# Test receive functionality
run_test "Receive Test" "receive" \
30
}
# Load configuration from file
load_configuration() {
local config_file="$1"
if [[ ! -f "$config_file" ]]; then
print_error "Configuration file not found: $config_file"
exit 1
fi
print_info "Loading configuration from $config_file"
if command -v jq >/dev/null 2>&1; then
local tests=$(jq -c '.tests[]' "$config_file" 2>/dev/null)
if [[ $? -eq 0 ]]; then
echo "$tests" | while read -r test; do
local name=$(echo "$test" | jq -r '.name // "Unnamed Test"')
local type=$(echo "$test" | jq -r '.type // "send"')
local to=$(echo "$test" | jq -r '.to // "test@local"')
local from=$(echo "$test" | jq -r '.from // "sender@local"')
local subject=$(echo "$test" | jq -r '.subject // "Test Email"')
local body=$(echo "$test" | jq -r '.body // "Test body"')
local html=$(echo "$test" | jq -r '.html // false')
local timeout=$(echo "$test" | jq -r '.timeout // 30')
run_test "$name" "$type" "$to" "$from" "$subject" "$body" "$html" "$timeout"
done
else
print_error "Invalid JSON in configuration file"
exit 1
fi
else
print_error "jq is required for JSON configuration files"
exit 1
fi
}
# Generate test report
generate_report() {
print_info "Generating test report..."
echo ""
echo "=========================================="
echo " EMAIL TEST REPORT "
echo "=========================================="
echo "Total Tests: $TOTAL_TESTS"
echo "Passed Tests: $PASSED_TESTS"
echo "Failed Tests: $FAILED_TESTS"
if [[ $TOTAL_TESTS -gt 0 ]]; then
local success_rate=$(( (PASSED_TESTS * 100) / TOTAL_TESTS ))
echo "Success Rate: ${success_rate}%"
fi
echo "Duration: $((SECONDS)) seconds"
echo "=========================================="
# Save detailed report if verbose mode
if [[ "$VERBOSE" == true ]]; then
echo "" >> "$REPORT_FILE"
echo "Test Summary:" >> "$REPORT_FILE"
echo "Total Tests: $TOTAL_TESTS" >> "$REPORT_FILE"
echo "Passed Tests: $PASSED_TESTS" >> "$REPORT_FILE"
echo "Failed Tests: $FAILED_TESTS" >> "$REPORT_FILE"
if [[ $TOTAL_TESTS -gt 0 ]]; then
local success_rate=$(( (PASSED_TESTS * 100) / TOTAL_TESTS ))
echo "Success Rate: ${success_rate}%" >> "$REPORT_FILE"
fi
echo "Duration: ${SECONDS} seconds" >> "$REPORT_FILE"
fi
# Generate JSON report if requested
if [[ "$OUTPUT_FORMAT" == "json" ]]; then
generate_json_report
elif [[ "$OUTPUT_FORMAT" == "csv" ]]; then
generate_csv_report
fi
}
# Generate JSON report
generate_json_report() {
local json_report_file="${REPORT_FILE%.*}.json"
local json="{\"timestamp\":\"$(date -Iseconds)\",\"total\":$TOTAL_TESTS,\"passed\":$PASSED_TESTS,\"failed\":$FAILED_TESTS,\"duration\":$SECONDS,\"tests\":["
local first=true
for result in "${TEST_RESULTS[@]}"; do
if [[ "$first" == true ]]; then
first=false
else
json+=","
fi
json+="$result"
done
json+="]}"
echo "$json" > "$json_report_file"
print_info "JSON report saved to: $json_report_file"
}
# Generate CSV report
generate_csv_report() {
local csv_report_file="${REPORT_FILE%.*}.csv"
echo "Test Name,Result,Details,Timestamp" > "$csv_report_file"
for result in "${TEST_RESULTS[@]}"; do
local name=$(echo "$result" | jq -r '.name' 2>/dev/null || echo "Unknown")
local res=$(echo "$result" | jq -r '.result' 2>/dev/null || echo "UNKNOWN")
local details=$(echo "$result" | jq -r '.details' 2>/dev/null || echo "No details")
local timestamp=$(date -Iseconds)
echo "\"$name\",\"$res\",\"$details\",\"$timestamp\"" >> "$csv_report_file"
done
print_info "CSV report saved to: $csv_report_file"
}
# Clean up test environment
cleanup_test_environment() {
if [[ "$CLEANUP" == true ]]; then
print_info "Cleaning up test environment..."
clear_mailhog_messages
fi
# Remove temporary files
rm -f /tmp/email_test_*
}
# Main execution
main() {
local start_time=$(date +%s)
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_usage
exit 0
;;
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-s|--scenario)
TEST_SCENARIO="$2"
shift 2
;;
--url)
MAILHOG_URL="$2"
shift 2
;;
--smtp-host)
SMTP_HOST="$2"
shift 2
;;
--smtp-port)
SMTP_PORT="$2"
shift 2
;;
-t|--timeout)
TIMEOUT="$2"
shift 2
;;
-v|--verbose)
VERBOSE=true
shift
;;
--no-cleanup)
CLEANUP=false
shift
;;
--output)
OUTPUT_FORMAT="$2"
shift 2
;;
--report-file)
REPORT_FILE="$2"
shift 2
;;
*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Validate output format
case "$OUTPUT_FORMAT" in
"text"|"json"|"csv")
;;
*)
print_error "Invalid output format: $OUTPUT_FORMAT. Use text, json, or csv."
exit 1
;;
esac
print_info "Starting email testing workflow..."
print_info "Scenario: $TEST_SCENARIO"
print_info "MailHog URL: $MAILHOG_URL"
print_info "SMTP Server: $SMTP_HOST:$SMTP_PORT"
# Initialize test environment
init_test_environment
# Run tests based on scenario or configuration
if [[ -n "$CONFIG_FILE" ]]; then
load_configuration "$CONFIG_FILE"
else
case "$TEST_SCENARIO" in
"basic")
run_basic_scenario
;;
"html")
run_html_scenario
;;
"attachments")
run_attachments_scenario
;;
"bulk")
run_bulk_scenario
;;
"performance")
run_performance_scenario
;;
"integration")
run_integration_scenario
;;
*)
print_error "Unknown test scenario: $TEST_SCENARIO"
show_usage
exit 1
;;
esac
fi
# Generate report
generate_report
# Clean up
cleanup_test_environment
# Exit with appropriate code
local end_time=$(date +%s)
local duration=$((end_time - start_time))
print_info "Test workflow completed in ${duration} seconds"
if [[ $FAILED_TESTS -eq 0 ]]; then
print_success "All tests passed!"
exit 0
else
print_error "$FAILED_TESTS test(s) failed"
exit 1
fi
}
# Run main function
main "$@"