Last active
July 26, 2024 00:58
-
-
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'.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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