Skip to content

Instantly share code, notes, and snippets.

@cyberpunk042
Last active July 26, 2024 00:58
Show Gist options
  • Save cyberpunk042/b58c3daf576458166ed41f9933ebd007 to your computer and use it in GitHub Desktop.
Save cyberpunk042/b58c3daf576458166ed41f9933ebd007 to your computer and use it in GitHub Desktop.
Docker-Compose setup script - HTTP:5080 to Flask to [Mailhog | Prod Smtp] - The script start up a mailhog container for smtp local testing when option "test" is chosen, or connect directly to the remote smtp service when option "prod" is chosen. A Python Flash app serves as the front, ready to listen on 'http://localhost:5080/send-email'.
#!/bin/bash
# Variables
PROJECT_DIR="email_service"
FLASK_APP_FILE="app.py"
DOCKERFILE="Dockerfile"
REQUIREMENTS_FILE="requirements.txt"
DOCKER_COMPOSE_FILE="docker-compose.yml"
# Default values for testing with MailHog
DEFAULT_TEST_MAIL_SERVER="mailhog"
DEFAULT_TEST_MAIL_PORT=1025
DEFAULT_TEST_MAIL_USE_TLS=false
DEFAULT_TEST_MAIL_USE_SSL=false
DEFAULT_TEST_MAIL_USERNAME=""
DEFAULT_TEST_MAIL_PASSWORD=""
DEFAULT_TEST_MAIL_DEFAULT_SENDER_NAME="Sender Name"
DEFAULT_TEST_MAIL_DEFAULT_SENDER_EMAIL="[email protected]"
# Default values for production with neo SMTP server
DEFAULT_PROD_MAIL_SERVER="smtp0001.neo.space"
DEFAULT_PROD_MAIL_PORT=465
DEFAULT_PROD_MAIL_USE_TLS=false
DEFAULT_PROD_MAIL_USE_SSL=true
DEFAULT_PROD_MAIL_USERNAME="[email protected]"
DEFAULT_PROD_MAIL_PASSWORD=""
DEFAULT_PROD_MAIL_DEFAULT_SENDER_NAME="Me.Name"
DEFAULT_PROD_MAIL_DEFAULT_SENDER_EMAIL="[email protected]"
# Logging functions
function log() {
echo "[INFO] $1"
}
function error() {
echo "[ERROR] $1" >&2
exit 1
}
# Function to check if a command exists
function check_command() {
if ! command -v $1 &> /dev/null; then
error "$1 could not be found. Please install it and run the script again."
fi
}
# Function to prompt for input with a default value
function prompt_for_input() {
local var_name=$1
local prompt_message=$2
local default_value=$3
read -p "$prompt_message [$default_value]: " input
if [ -z "$input" ]; then
input=$default_value
fi
eval "$var_name='$input'"
}
# Function to parse CLI arguments
function parse_args() {
while [ $# -gt 0 ]; do
case "$1" in
--env=*)
ENVIRONMENT="${1#*=}"
;;
--mail-server=*)
MAIL_SERVER="${1#*=}"
;;
--mail-port=*)
MAIL_PORT="${1#*=}"
;;
--mail-use-tls=*)
MAIL_USE_TLS="${1#*=}"
;;
--mail-use-ssl=*)
MAIL_USE_SSL="${1#*=}"
;;
--mail-username=*)
MAIL_USERNAME="${1#*=}"
;;
--mail-password=*)
MAIL_PASSWORD="${1#*=}"
;;
--mail-default-sender-name=*)
MAIL_DEFAULT_SENDER_NAME="${1#*=}"
;;
--mail-default-sender-email=*)
MAIL_DEFAULT_SENDER_EMAIL="${1#*=}"
;;
*)
error "Unknown argument: $1"
;;
esac
shift
done
}
# Function to create project structure
function create_project_structure() {
mkdir -p $PROJECT_DIR
cd $PROJECT_DIR || error "Failed to change directory to $PROJECT_DIR"
}
# Function to create Dockerfile
function create_dockerfile() {
cat > $DOCKERFILE <<EOL
FROM python:3.9-slim
WORKDIR /app
COPY $REQUIREMENTS_FILE $REQUIREMENTS_FILE
RUN pip install -r $REQUIREMENTS_FILE
COPY $FLASK_APP_FILE $FLASK_APP_FILE
CMD ["python", "$FLASK_APP_FILE"]
EOL
}
# Function to create requirements.txt
function create_requirements() {
cat > $REQUIREMENTS_FILE <<EOL
Flask==2.0.1
Werkzeug==2.0.1
Flask-Mail==0.9.1
EOL
}
# Function to create Flask app
function create_flask_app() {
cat > $FLASK_APP_FILE <<EOL
from flask import Flask, request, jsonify
from flask_mail import Mail, Message
import os
import logging
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.DEBUG)
app.config.update(
MAIL_SERVER=os.environ.get('MAIL_SERVER', 'localhost'),
MAIL_PORT=int(os.environ.get('MAIL_PORT', 1025)), # Default to MailHog's SMTP port
MAIL_USE_TLS=os.environ.get('MAIL_USE_TLS', 'false').lower() in ['true', '1', 'yes'],
MAIL_USE_SSL=os.environ.get('MAIL_USE_SSL', 'false').lower() in ['true', '1', 'yes'],
MAIL_USERNAME=os.environ.get('MAIL_USERNAME', ''),
MAIL_PASSWORD=os.environ.get('MAIL_PASSWORD', ''),
MAIL_DEFAULT_SENDER=(os.environ.get('MAIL_DEFAULT_SENDER_NAME', 'Your Name'), os.environ.get('MAIL_DEFAULT_SENDER_EMAIL', '[email protected]'))
)
mail = Mail(app)
@app.route('/send-email', methods=['POST'])
def send_email():
data = request.get_json()
email = data.get('email')
subject = data.get('subject')
message = data.get('message')
if not email or not subject or not message:
return jsonify({"status": "error", "message": "Missing email, subject or message"}), 400
msg = Message(subject, recipients=[email])
msg.body = message
try:
mail.send(msg)
app.logger.info("Email sent successfully")
return jsonify({"status": "success", "message": "Email sent successfully"}), 200
except Exception as e:
app.logger.error(f"Failed to send email: {e}")
return jsonify({"status": "error", "message": str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5080)
EOL
}
# Function to create docker-compose.yml
function create_docker_compose() {
cat > $DOCKER_COMPOSE_FILE <<EOL
version: '3.3'
services:
flask-app:
build: .
ports:
- "5080:5080"
environment:
MAIL_SERVER: ${MAIL_SERVER}
MAIL_PORT: ${MAIL_PORT}
MAIL_USE_TLS: ${MAIL_USE_TLS}
MAIL_USE_SSL: ${MAIL_USE_SSL}
MAIL_USERNAME: ${MAIL_USERNAME}
MAIL_PASSWORD: ${MAIL_PASSWORD}
MAIL_DEFAULT_SENDER_NAME: ${MAIL_DEFAULT_SENDER_NAME}
MAIL_DEFAULT_SENDER_EMAIL: ${MAIL_DEFAULT_SENDER_EMAIL}
depends_on:
- mailhog
mailhog:
image: mailhog/mailhog
container_name: mailhog
ports:
- "1025:1025" # SMTP server
- "8025:8025" # Web UI
EOL
}
# Function to set up Docker
function setup_docker() {
if ! docker info > /dev/null 2>&1; then
log "Docker is not running. Starting Docker..."
sudo service docker start || error "Failed to start Docker."
fi
if ! command -v docker-compose &> /dev/null; then
log "Docker Compose is not installed. Installing Docker Compose..."
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose || error "Failed to download Docker Compose."
sudo chmod +x /usr/local/bin/docker-compose || error "Failed to set executable permissions for Docker Compose."
fi
}
# Function to build and run Docker containers
function build_and_run() {
log "Building Docker containers..."
docker-compose build || error "Failed to build Docker containers."
log "Starting Docker containers..."
docker-compose up -d || error "Failed to start Docker containers."
log "Setup complete. The Flask app is running on port 5080, and MailHog is running on port 8025."
log "To send an email, make a POST request to http://localhost:5080/send-email with the following JSON body:"
echo '{
"email": "[email protected]",
"subject": "Test Email",
"message": "Hello world"
}'
log "To view emails, open your browser and go to http://localhost:8025"
}
# Main script execution
check_command "docker"
check_command "curl"
log "Welcome to the Email Service setup script."
# Parse CLI arguments
parse_args "$@"
# Prompt for environment
if [ -z "$ENVIRONMENT" ]; then
prompt_for_input ENVIRONMENT "Enter the environment (test/prod)" "test"
fi
# Set default values based on environment
if [ "$ENVIRONMENT" == "test" ]; then
MAIL_SERVER=${MAIL_SERVER:-$DEFAULT_TEST_MAIL_SERVER}
MAIL_PORT=${MAIL_PORT:-$DEFAULT_TEST_MAIL_PORT}
MAIL_USE_TLS=${MAIL_USE_TLS:-$DEFAULT_TEST_MAIL_USE_TLS}
MAIL_USE_SSL=${MAIL_USE_SSL:-$DEFAULT_TEST_MAIL_USE_SSL}
MAIL_USERNAME=${MAIL_USERNAME:-$DEFAULT_TEST_MAIL_USERNAME}
MAIL_PASSWORD=${MAIL_PASSWORD:-$DEFAULT_TEST_MAIL_PASSWORD}
MAIL_DEFAULT_SENDER_NAME=${MAIL_DEFAULT_SENDER_NAME:-$DEFAULT_TEST_MAIL_DEFAULT_SENDER_NAME}
MAIL_DEFAULT_SENDER_EMAIL=${MAIL_DEFAULT_SENDER_EMAIL:-$DEFAULT_TEST_MAIL_DEFAULT_SENDER_EMAIL}
else
MAIL_SERVER=${MAIL_SERVER:-$DEFAULT_PROD_MAIL_SERVER}
MAIL_PORT=${MAIL_PORT:-$DEFAULT_PROD_MAIL_PORT}
MAIL_USE_TLS=${MAIL_USE_TLS:-$DEFAULT_PROD_MAIL_USE_TLS}
MAIL_USE_SSL=${MAIL_USE_SSL:-$DEFAULT_PROD_MAIL_USE_SSL}
MAIL_USERNAME=${MAIL_USERNAME:-$DEFAULT_PROD_MAIL_USERNAME}
MAIL_PASSWORD=${MAIL_PASSWORD:-$DEFAULT_PROD_MAIL_PASSWORD}
MAIL_DEFAULT_SENDER_NAME=${MAIL_DEFAULT_SENDER_NAME:-$DEFAULT_PROD_MAIL_DEFAULT_SENDER_NAME}
MAIL_DEFAULT_SENDER_EMAIL=${MAIL_DEFAULT_SENDER_EMAIL:-$DEFAULT_PROD_MAIL_DEFAULT_SENDER_EMAIL}
fi
# Prompt for values if not provided via CLI arguments
prompt_for_input MAIL_SERVER "Enter the SMTP server" $MAIL_SERVER
prompt_for_input MAIL_PORT "Enter the SMTP port" $MAIL_PORT
prompt_for_input MAIL_USE_TLS "Use TLS? (true/false)" $MAIL_USE_TLS
prompt_for_input MAIL_USE_SSL "Use SSL? (true/false)" $MAIL_USE_SSL
prompt_for_input MAIL_USERNAME "Enter the SMTP username" $MAIL_USERNAME
prompt_for_input MAIL_PASSWORD "Enter the SMTP password" $MAIL_PASSWORD
prompt_for_input MAIL_DEFAULT_SENDER_NAME "Enter the default sender name" $MAIL_DEFAULT_SENDER_NAME
prompt_for_input MAIL_DEFAULT_SENDER_EMAIL "Enter the default sender email" $MAIL_DEFAULT_SENDER_EMAIL
# Export environment variables for Docker Compose
export MAIL_SERVER MAIL_PORT MAIL_USE_TLS MAIL_USE_SSL MAIL_USERNAME MAIL_PASSWORD MAIL_DEFAULT_SENDER_NAME MAIL_DEFAULT_SENDER_EMAIL
log "Creating project structure..."
create_project_structure
log "Creating Dockerfile..."
create_dockerfile
log "Creating requirements.txt..."
create_requirements
log "Creating Flask app..."
create_flask_app
log "Creating docker-compose.yml..."
create_docker_compose
log "Setting up Docker..."
setup_docker
log "Building and running Docker containers..."
build_and_run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment