# SMTP 이메일 발신 시스템 설정 가이드 이메일 인증 및 비밀번호 재설정을 위한 SMTP 서버 설정 방법입니다. ## 📋 목차 - [방법 1: Python Flask-Mail (권장)](#방법-1-python-flask-mail-권장) - [방법 2: Docker MailHog (개발용)](#방법-2-docker-mailhog-개발용) - [방법 3: Docker Postfix (운영용)](#방법-3-docker-postfix-운영용) - [방법 4: 외부 SMTP 서비스](#방법-4-외부-smtp-서비스) --- ## 방법 1: Python Flask-Mail (권장) ⭐ Flask 앱에 직접 통합하는 가장 간단한 방법입니다. ### 1-1. 설치 ```bash cd /home/ckh08045/Tr_Code source bin/activate pip install Flask-Mail pip freeze > requirements.txt ``` ### 1-2. .env 설정 ```bash # SMTP 설정 추가 MAIL_SERVER=smtp.gmail.com MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USE_SSL=False MAIL_USERNAME=your-email@gmail.com MAIL_PASSWORD=your-app-password MAIL_DEFAULT_SENDER=your-email@gmail.com ``` **Gmail 앱 비밀번호 생성:** 1. Google 계정 → 보안 2. 2단계 인증 활성화 3. 앱 비밀번호 생성 4. `.env`에 입력 ### 1-3. app.py에 추가 ```python from flask_mail import Mail, Message # Flask-Mail 설정 app.config['MAIL_SERVER'] = os.environ.get('MAIL_SERVER', 'smtp.gmail.com') app.config['MAIL_PORT'] = int(os.environ.get('MAIL_PORT', 587)) app.config['MAIL_USE_TLS'] = os.environ.get('MAIL_USE_TLS', 'True').lower() == 'true' app.config['MAIL_USE_SSL'] = os.environ.get('MAIL_USE_SSL', 'False').lower() == 'true' app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') app.config['MAIL_DEFAULT_SENDER'] = os.environ.get('MAIL_DEFAULT_SENDER') mail = Mail(app) def send_reset_email(to_email, reset_token, employee_id): """비밀번호 재설정 이메일 전송""" reset_url = url_for('reset_password', token=reset_token, _external=True) msg = Message( subject='[1호선 고장코드] 비밀번호 재설정', recipients=[to_email] ) msg.body = f""" 안녕하세요, 비밀번호 재설정을 요청하셨습니다. 사번: {employee_id} 아래 링크를 클릭하여 비밀번호를 재설정하세요: {reset_url} 이 링크는 1시간 동안 유효합니다. 본인이 요청하지 않았다면 이 이메일을 무시하세요. --- 부산교통공사 1호선 차량 고장코드 시스템 """ msg.html = f"""

비밀번호 재설정

안녕하세요,

비밀번호 재설정을 요청하셨습니다.

사번: {employee_id}

아래 버튼을 클릭하여 비밀번호를 재설정하세요:

비밀번호 재설정

이 링크는 1시간 동안 유효합니다.

본인이 요청하지 않았다면 이 이메일을 무시하세요.


부산교통공사 1호선 차량 고장코드 시스템

""" try: mail.send(msg) return True, "이메일이 전송되었습니다." except Exception as e: print(f"이메일 전송 실패: {str(e)}") return False, f"이메일 전송에 실패했습니다: {str(e)}" ``` ### 1-4. forgot_password 라우트 수정 ```python # 재설정 토큰 생성 후 reset_token = secrets.token_urlsafe(32) session[f"reset_token_{reset_token}"] = { "employee_id": employee_id, "email": user["email"], "expires": (datetime.now() + timedelta(hours=1)).isoformat() } # 이메일 전송 success, message = send_reset_email(user["email"], reset_token, employee_id) if success: return render_template( "forgot_password.html", app_name=APP_NAME, success="등록된 이메일로 비밀번호 재설정 링크를 전송했습니다." ) else: return render_template( "forgot_password.html", app_name=APP_NAME, error=message ) ``` ### 1-5. 장단점 **장점:** - ✅ 설치/설정 간단 - ✅ Flask 앱과 완벽 통합 - ✅ 추가 서버 불필요 - ✅ Gmail, Naver 등 기존 계정 사용 가능 **단점:** - ❌ 메일 서버 의존성 - ❌ 발신 제한 (Gmail: 하루 500통) --- ## 방법 2: Docker MailHog (개발용) 🧪 개발/테스트 환경에서 실제 이메일 전송 없이 테스트하는 방법입니다. ### 2-1. Docker Compose 설정 ```yaml # docker-compose.yml (기존 Supabase에 추가) services: mailhog: image: mailhog/mailhog:latest container_name: mailhog ports: - "1025:1025" # SMTP - "8025:8025" # Web UI networks: - tr_code_network restart: unless-stopped networks: tr_code_network: external: true ``` ### 2-2. 실행 ```bash docker-compose up -d mailhog ``` ### 2-3. .env 설정 ```bash # 개발 환경 MAIL_SERVER=localhost MAIL_PORT=1025 MAIL_USE_TLS=False MAIL_USE_SSL=False MAIL_USERNAME= MAIL_PASSWORD= MAIL_DEFAULT_SENDER=noreply@tr-code.local ``` ### 2-4. 이메일 확인 브라우저에서 `http://192.168.0.180:8025` 접속 - 전송된 모든 이메일 확인 가능 - 실제 전송은 안 됨 (개발용) ### 2-5. 장단점 **장점:** - ✅ 실제 이메일 전송 없이 테스트 - ✅ 웹 UI로 쉽게 확인 - ✅ 설정 간단 **단점:** - ❌ 개발용으로만 사용 가능 - ❌ 실제 이메일 전송 안 됨 --- ## 방법 3: Docker Postfix (운영용) 🚀 자체 SMTP 서버를 운영하는 방법입니다. ### 3-1. Docker Compose 설정 ```yaml services: postfix: image: boky/postfix:latest container_name: postfix environment: - ALLOWED_SENDER_DOMAINS=humetro.busan.kr - HOSTNAME=mail.tr-code.local ports: - "25:25" # SMTP - "587:587" # SMTP with TLS volumes: - ./postfix-data:/var/spool/postfix networks: - tr_code_network restart: unless-stopped ``` ### 3-2. .env 설정 ```bash MAIL_SERVER=localhost MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USE_SSL=False MAIL_USERNAME= MAIL_PASSWORD= MAIL_DEFAULT_SENDER=noreply@humetro.busan.kr ``` ### 3-3. DNS 설정 (필수) 도메인 DNS에 다음 레코드 추가: ``` MX @ 10 mail.yourdomain.com A mail 192.168.0.180 TXT @ "v=spf1 ip4:192.168.0.180 ~all" ``` ### 3-4. 장단점 **장점:** - ✅ 완전한 제어 - ✅ 발신 제한 없음 - ✅ 커스터마이징 가능 **단점:** - ❌ 설정 복잡 - ❌ 스팸 필터링 이슈 - ❌ DNS/IP 평판 관리 필요 --- ## 방법 4: 외부 SMTP 서비스 📧 전문 이메일 서비스를 사용하는 방법입니다. ### 4-1. SendGrid (추천) **가격:** 무료 티어 100통/일 ```bash # .env MAIL_SERVER=smtp.sendgrid.net MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USERNAME=apikey MAIL_PASSWORD=your_sendgrid_api_key MAIL_DEFAULT_SENDER=noreply@yourdomain.com ``` **장점:** - ✅ 높은 전달률 - ✅ 통계/분석 제공 - ✅ 무료 티어 제공 ### 4-2. Gmail **가격:** 무료 (500통/일 제한) ```bash # .env MAIL_SERVER=smtp.gmail.com MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USERNAME=your-email@gmail.com MAIL_PASSWORD=your-app-password ``` ### 4-3. Naver **가격:** 무료 (제한 있음) ```bash # .env MAIL_SERVER=smtp.naver.com MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USERNAME=your-id@naver.com MAIL_PASSWORD=your-password ``` ### 4-4. AWS SES **가격:** 0.10USD / 1000통 ```bash # .env MAIL_SERVER=email-smtp.ap-northeast-2.amazonaws.com MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USERNAME=your_access_key MAIL_PASSWORD=your_secret_key ``` --- ## 💡 권장 사항 ### 개발/테스트 환경 ``` MailHog (Docker) → 가장 간단 ``` ### 운영 환경 (소규모) ``` Gmail + Flask-Mail → 빠른 구축 ``` ### 운영 환경 (대규모) ``` SendGrid 또는 AWS SES → 안정성 ``` ### 내부망 전용 ``` Postfix (Docker) → 완전한 제어 ``` --- ## 🔧 설치 스크립트 ### Flask-Mail 설치 및 설정 ```bash cd /home/ckh08045/Tr_Code source bin/activate pip install Flask-Mail pip freeze > requirements.txt # .env에 설정 추가 cat >> .env << 'EOF' # SMTP 설정 (Gmail 예시) MAIL_SERVER=smtp.gmail.com MAIL_PORT=587 MAIL_USE_TLS=True MAIL_USE_SSL=False MAIL_USERNAME=your-email@gmail.com MAIL_PASSWORD=your-app-password MAIL_DEFAULT_SENDER=your-email@gmail.com EOF # 서비스 재시작 sudo systemctl restart Tr_Code ``` ### MailHog (Docker) 설치 ```bash cd /home/ckh08045/Tr_Code # docker-compose.yml 생성 또는 수정 docker-compose up -d mailhog # 웹 UI 접속 echo "MailHog UI: http://192.168.0.180:8025" ``` --- ## 📝 이메일 템플릿 예시 ### 비밀번호 재설정 ```html

비밀번호 재설정

안녕하세요, {{ name }}님

비밀번호 재설정을 요청하셨습니다.

비밀번호 재설정

이 링크는 1시간 동안 유효합니다.

``` ### 회원가입 인증 ```html

회원가입 인증

환영합니다, {{ name }}님!

아래 버튼을 클릭하여 이메일을 인증하세요:

이메일 인증
``` --- ## 🐛 문제 해결 ### Gmail 전송 실패 **원인:** 앱 비밀번호 미설정 **해결:** 1. Google 계정 → 보안 2. 2단계 인증 활성화 3. 앱 비밀번호 생성 ### SMTP 연결 실패 ```bash # 포트 확인 telnet smtp.gmail.com 587 # 방화벽 확인 sudo ufw allow 587/tcp ``` ### MailHog 접속 안됨 ```bash # 컨테이너 상태 확인 docker ps | grep mailhog # 로그 확인 docker logs mailhog # 재시작 docker restart mailhog ``` --- ## 🔒 보안 고려사항 1. **환경변수 사용**: 비밀번호를 코드에 하드코딩하지 마세요 2. **TLS 사용**: 암호화된 연결 사용 3. **Rate Limiting**: 과도한 이메일 전송 방지 4. **토큰 만료**: 재설정 링크에 시간 제한 설정 5. **.env 보호**: `.gitignore`에 추가 --- ## 📊 비교표 | 방법 | 설정 난이도 | 비용 | 전달률 | 제어 | 추천 | |------|-----------|------|--------|------|------| | Flask-Mail + Gmail | ⭐ 쉬움 | 무료 | 높음 | 낮음 | 소규모 | | MailHog | ⭐ 쉬움 | 무료 | N/A | 높음 | 개발 | | Postfix | ⭐⭐⭐ 어려움 | 무료 | 낮음 | 높음 | 내부망 | | SendGrid | ⭐⭐ 보통 | 무료/유료 | 높음 | 보통 | 운영 | | AWS SES | ⭐⭐ 보통 | 유료 | 높음 | 보통 | 대규모 | --- **작성일**: 2025-10-15 **권장 방법**: Flask-Mail + Gmail (개발), SendGrid (운영)