개요
이 튜토리얼에서는 MongoDB , Flask, 셀러리를 사용하여 뉴스레터 플랫폼을 빌드 방법을 학습 수 있습니다. 이 애플리케이션 통해 사용자는 뉴스레터를 구독 하고 관리자는 배치 이메일을 비동기적으로 관리 하고 보낼 수 있습니다.
Flask
Flask는 프로젝트 전반에서 개발자에게 일관성 제공하는 내장 경량 웹 애플리케이션 프레임워크 입니다. 자세한 내용은 Flask 웹페이지를 참조하세요.
셀러리
셀러리는 대량의 메시지를 효율적으로 처리하는 오픈 소스 분산된 작업 대기열입니다. 비동기 처리 및 작업 스케줄링을 지원합니다. 자세한 내용은 셀러리 웹 페이지를 참조하세요.
튜토리얼
이 튜토리얼에서는 JavaScript, Flask 및 MongoDB 사용하는 뉴스레터 플랫폼 샘플 프로젝트 Github 리포지토리에서 샘플 애플리케이션 다시 만듭니다.
전제 조건
이 튜토리얼을 시작하기 전에 다음 구성 요소가 설치 및 설정하다 있는지 확인하십시오.
MongoDB cluster. Atlas 사용하는 것이 좋습니다. Atlas cluster 만드는 방법을 학습 Atlas 설명서의 Get Started with Atlas (Atlas 시작하기) 페이지를 참조하세요.
클러스터 에 있는
newsletter데이터베이스 . 자세한 내용은 Atlas 가이드의 데이터베이스 생성 페이지를 참조하세요.Gmail 을 SMTP 서버로 사용할 수 있습니다. SMTP 서버에 대한 자세한 내용은 단순 메일 전송 프로토콜 위키백과 페이지를 참조하세요.
설정
프로젝트 디렉토리 및 구조 만들기
프로젝트 디렉토리 의 이름은 newsletter입니다. 디렉토리 생성하고 터미널에서 다음 명령을 실행 디렉토리로 이동합니다.
mkdir newsletter cd newsletter
다음 파일에는 애플리케이션 의 코드가 들어 있습니다.
app.py: Flask 애플리케이션 의 기본 진입 점 .config.py: MongoDB 연결 URI, 메일 서버 구성, 셀러리 브로커 연결 및 기타 환경별 변수를 포함한 애플리케이션 의 구성 설정입니다.tasks.py: 이메일을 비동기적으로 전송하는 배경 작업을 정의합니다.routes.py: 애플리케이션 이 응답하는 경로(URL)를 정의합니다.
애플리케이션 애플리케이션 모듈식으로 만들고 유지 관리하기 쉽게 만들 수 있는 별도의 고려 사항으로 애플리케이션 구조화하는 것이 좋습니다.
프로젝트 디렉토리 에서 다음 구조를 만듭니다.
newsletter/ ├── app.py ├── config.py ├── routes.py ├── tasks.py ├── templates/ │ ├── admin.html │ └── subscribe.html └── static/ └── styles.css
필수 Python 패키지 설치
애플리케이션 다음 라이브러리를 사용합니다.
애플리케이션 에서 이메일을 전송하기위한 Flask-mail
팁
가상 환경 사용
Python 가상 환경 을 사용하면 프로젝트마다 다양한 버전의 라이브러리를 설치할 수 있습니다. pip 명령을 실행 전에 virtualenv 가 활성화되어 있는지 확인합니다.
터미널에서 다음 pip 명령을 실행하여 종속성을 설치합니다.
pip install flask-pymongo Flask-Mail celery
애플리케이션 구성
config.py 파일 에는 다음 작업을 수행하기 위한 설정 및 자격 증명 포함되어 있습니다.
메시지 브로커로 셀러리를 래빗MQ에 연결
Gmail을 SMTP 서버 로 사용하도록 Flask-mail 구성
애플리케이션 MongoDB deployment 에 연결
config.py 파일 에 다음 코드를 추가하여 필요한 구성을 정의합니다.
import os class Config: MAIL_USERNAME = '<username>' # Your email address without '@gmail.com' MAIL_PASSWORD = '<app password>' MAIL_DEFAULT_SENDER = '<email address>' MONGO_URI = '<mongodb connection string>' DATABASE_NAME = "newsletter" ALLOWED_IPS = ['127.0.0.1'] MAIL_SERVER = 'smtp.gmail.com' MAIL_PORT = 587 MAIL_USE_TLS = True CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' RESULT_BACKEND = MONGO_URI + '/celery_results'
애플리케이션 에서 이메일을 보내 활성화 Gmail 자격 증명 과 이메일 (MAIL_USERNAME, MAIL_PASSWORD, MAIL_DEFAULT_SENDER)을 제공해야 합니다. 보안을 위해 프라이머리 비밀번호를 사용하는 대신 사용할 앱 비밀번호를 생성하는 것이 좋습니다. 자세한 내용은 Google 계정의 앱 비밀번호 설정 을 참조하세요.
또한 MONGO_URI 환경 변수로 설정하다 연결 문자열 제공해야 합니다. 자세한 내용은 이 가이드의 연결 문자열 만들기 섹션을 참조하세요.
제공된 셀러리 브로커 URL (CELERY_BROKER_URL)은 래빗MQ를 브로커로 지정하지만, 다른 구현을 지원 이 URL 사용자 지정할 수 있습니다. 자세한 내용은 셀러리 문서의 브로커 설정 섹션을 참조하세요.
ALLOWED_IPS 목록은 Send
Newsletter 페이지에 대한 액세스 제어하는 데 사용됩니다. 나머지 변수는 Flask 및 셀러리 구성 요소를 구성합니다.
Flask, MongoDB 및 셀러리 초기화
app.py 파일 애플리케이션 의 핵심 구성 요소를 초기화하고 구성합니다. 다음 작업을 수행합니다.
Flask 애플리케이션 생성하고 구성 상수를 로드합니다.
앱의 메일 서버 설정을 사용하여 Flask-mail 인스턴스 초기화합니다.
PyMongo 운전자 사용하여
newsletterMongoDB database 에 연결합니다.Flask 앱 과 선택한 브로커로 구성된 셀러리 인스턴스 생성합니다.
app.py 파일 에 다음 코드를 추가하여 Flask, MongoDB 및 Celery를 초기화합니다.
from flask import Flask from flask_mail import Mail from flask_pymongo import PyMongo from celery import Celery # Create a Flask application app = Flask(__name__) app.config.from_object('config.Config') # Create a Flask-Mail instance mail = Mail(app) # Connect to MongoDB client = PyMongo(app).cx db = client[app.config['DATABASE_NAME']] # Create a Celery instance celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) celery.conf.update(app.config) from routes import * from tasks import * if __name__ == '__main__': app.run(debug=True)
셀러리 작업 만들기
셀러리 작업 app.py 파일 에서 인스턴스화된 구성 요소를 사용하여 구독자에게 뉴스레터 이메일 보냅니다.
@celery.task() 데코레이터는 함수를 셀러리 작업 으로 등록합니다. bind=True 을 설정하면 함수가 작업 인스턴스 self 인수로 수신하여 셀러리 작업 메서드 및 메타데이터 액세스 할 수 있음을 의미합니다. 작업에 대한 자세한 내용은 셀러리를 참조하세요. 앱. 작업 API 문서를 참조하세요.
이 작업 Flask의 HTTP 요청 주기 외부에서 실행되므로 이메일 로직을 with
app.app_context() 차단 으로 래핑하여 애플리케이션 컨텍스트를 수동으로 제공해야 합니다. 이렇게 하면 Flask-mail mail 인스턴스 및 newsletter MongoDB database 에 대한 PyMongo 연결과 같은 다른 구성 요소에 액세스 할 수 있습니다.
이 함수는 subscribers 목록을 반복하고,Flask-mail Message 클래스를 사용하여 이메일 만든 다음 mail 객체 사용하여 각 사용자에게 보냅니다. 각 이메일 전송된 후 MongoDB deliveries 컬렉션 에 문서 삽입하여 메시지가 전송되었음을 기록 하여 전송을 기록합니다. 각 이메일 작업은 try 차단 으로 래핑되어 오류 발생 시 실패가 기록되고 데이터베이스 잘못된 전송 기록 으로 업데이트되지 않습니다.
tasks.py 파일 에 다음 코드를 추가하여 send_emails() 함수를 정의합니다.
from flask_mail import Message from app import app, mail, db, celery from datetime import datetime def send_emails(self, subscribers, title, body): with app.app_context(): for subscriber in subscribers: try: print(f"Sending email to {subscriber['email']}") msg = Message(title, recipients=[subscriber['email']]) msg.body = body mail.send(msg) db.deliveries.insert_one({ 'email': subscriber['email'], 'title': title, 'body': body, 'delivered_at': datetime.utcnow() }) print("Email sent") except Exception as e: print(f"Failed to send email to {subscriber['email']}: {str(e)}") return {'result': 'All emails sent'}
경로 정의
Flask에서 @app.route() 데코레이터는 특정 함수에 URL 경로를 할당합니다. 다음 코드에서는 루트(/), /admin, /subscribe 및 /send-newsletters 경로를 정의하는 데 사용됩니다. 선택적 methods 매개변수는 일부 인스턴스에서 허용되는 HTTP 메서드 목록을 정의하는 데 사용됩니다.
@app.before_request() 데코레이터는 모든 요청 전에 실행 함수를 설정합니다. 이 경우 함수는 admin 페이지에 대한 액세스 config.py 파일 에 정의된 ALLOWED_IPS 매개변수에 나열된 IP 주소로 제한하여 몇 가지 기본 보안을 제공합니다. 특히 localhost에 대해서만 액세스 허용됩니다.
루트 및 /admin 라우팅은 render_template() 메서드를 사용하여 페이지를 렌더링합니다. /subscribe 및 /send-newsletters 는 request.form[] 의 액세스 요청 매개 변수를 라우팅하여 명령을 실행한 다음 HTTP 응답을 반환합니다.
routes.py 파일 에 다음 코드를 추가하여 경로를 정의합니다.
from flask import render_template, request, abort, jsonify from app import app, db from tasks import send_emails def limit_remote_addr(): if 'X-Forwarded-For' in request.headers: remote_addr = request.headers['X-Forwarded-For'].split(',')[0] else: remote_addr = request.remote_addr if request.endpoint == 'admin' and remote_addr not in app.config['ALLOWED_IPS']: abort(403) def home(): return render_template('subscribe.html') def admin(): return render_template('admin.html') def subscribe(): first_name = request.form['firstname'] last_name = request.form['lastname'] email = request.form['email'] if db.users.find_one({'email': email}): return """ <div class="response error"> <span class="icon">✖</span> This email is already subscribed! </div> """, 409 db.users.insert_one({'firstname': first_name, 'lastname': last_name, 'email': email, 'subscribed': True}) return """ <div class="response success"> <span class="icon">✔</span> Subscribed successfully! </div> """, 200 def send_newsletters(): title = request.form['title'] body = request.form['body'] subscribers = list(db.users.find({'subscribed': True})) for subscriber in subscribers: subscriber['_id'] = str(subscriber['_id']) send_emails.apply_async(args=[subscribers, title, body]) return jsonify({'message': 'Emails are being sent!'}), 202
이 파일 에서 더 많은 보안 보호 기능을 추가하거나 애플리케이션 에 대한 사용자 대상 경고를 사용자 지정할 수 있습니다.
페이지 템플릿 만들기
templates 디렉토리 의 HTML 파일은 사용자 인터페이스를 정의하며 표준 HTML을 사용하여 작성됩니다. 이 애플리케이션 비동기 HTTP 요청을 사용하기 때문에 이러한 파일의 스크립트는 Fetch API 호출를 사용합니다. 이러한 스크립트는 시간 초과 및 오류도 처리하다 .
구독 페이지
다음 코드를 subscribe.html 파일 에 복사하여 Subscribe to Newsletter 페이지를 만듭니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Subscribe to Newsletter</title> <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> </head> <body> <h1>Subscribe to our Newsletter</h1> <form id="subscribe-form"> <label for="firstname">First Name:</label> <input type="text" id="firstname" name="firstname" required> <br> <label for="lastname">Last Name:</label> <input type="text" id="lastname" name="lastname" required> <br> <label for="email">Email:</label> <input type="email" id="email" name="email" required> <br> <button type="submit">Subscribe</button> </form> <div id="response"></div> <script> document.getElementById('subscribe-form').addEventListener('submit', function(event) { event.preventDefault(); var formData = new FormData(event.target); fetch('/subscribe', { method: 'POST', body: formData }).then(response => { if (!response.ok) { throw response; } return response.text(); }).then(data => { document.getElementById('response').innerHTML = data; document.getElementById('subscribe-form').reset(); setTimeout(() => { document.getElementById('response').innerHTML = ''; }, 3000); }).catch(error => { error.text().then(errorMessage => { document.getElementById('response').innerHTML = errorMessage; setTimeout(() => { document.getElementById('response').innerHTML = ''; }, 3000); }); }); }); </script> </body> </html>
관리자 페이지
관리자 페이지 스크립트 send_newsletter 호출의 성공 나타내는 경고 사용자에게 표시합니다.
다음 코드를 admin.html 파일 에 복사하여 Send Newsletter 페이지를 만듭니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Admin - Send Newsletter</title> <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> </head> <body> <h1>Send Newsletter</h1> <form id="admin-form"> <label for="title">Title:</label> <input type="text" id="title" name="title" required> <br> <label for="body">Body:</label> <textarea id="body" name="body" required></textarea> <br> <button type="submit">Send</button> </form> <div id="response"></div> <script> document.getElementById('admin-form').addEventListener('submit', function(event) { event.preventDefault(); var formData = new FormData(event.target); fetch('/send-newsletters', { method: 'POST', body: formData }) .then(response => response.json()) .then(() => { document.getElementById('response').innerText = 'Emails are being sent!'; setTimeout(() => { document.getElementById('response').innerText = ''; }, 3000); document.getElementById('admin-form').reset(); }) .catch(error => { document.getElementById('response').innerText = 'Error sending emails.'; setTimeout(() => { document.getElementById('response').innerText = ''; }, 3000); console.error('Error:', error); }); }); </script> </body> </html>
페이지 서식 지정
styles.css 파일 에 다음 코드를 추가하여 템플릿에 스타일시트 적용 할 수 있습니다.
body { font-family: system-ui; font-optical-sizing: auto; font-weight: 300; font-style: normal; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; background-color: #040100; } h1 { color: white; } form { background: #023430; padding: 30px 40px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); width: 100%; max-width: 400px; margin: 20px 0; } label { display: block; margin-bottom: 8px; font-weight: bold; color: white; } input[type="text"], input[type="email"], textarea { width: 100%; padding: 10px; margin-bottom: 10px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; } button { background: #00ED64; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; font-family: "Nunito", sans-serif; } button:hover { background: #00684A; } #response { margin-top: 20px; font-size: 16px; color: #28a745; } footer { text-align: center; padding: 20px; margin-top: 20px; font-size: 16px; color: #666; }
애플리케이션 테스트
이전 단계를 완료하면 MongoDB , Flask 및 Celery를 사용하여 뉴스레터 플랫폼을 관리 애플리케이션 작동하는 것입니다.
다음 단계에 따라 애플리케이션 테스트할 수 있습니다.
배경 서비스 시작
래빗MQ 노드 시작합니다. 자세한 내용은 운영 체제의 래빗MQ 설명서 를 참조하세요.
MacOS의 경우:
brew services start rabbitmq
Windows의 경우:
rabbitmq-service start
On Linux/Unix:
sudo systemctl start rabbitmq-server
구독자 만들기
브라우저에서 localhost:5000 로 이동하여 Subscribe to our Newsletter 페이지를 엽니다.
구독자 정보를 입력하고 Subscribe을(를) 클릭합니다.
새 구독자를 생성했는지 확인하려면 Atlas 열고 newsletter 데이터베이스 에서 users 컬렉션 으로 이동합니다.
뉴스레터 발송
브라우저에서 localhost:5000/admin 으로 이동하여 Send Newsletter 페이지를 엽니다. 뉴스레터 세부 정보를 입력하고 Send을 클릭합니다.
셀러리 작업자 로그 다음 이미지와 유사한 Email sent 로그 항목이 표시됩니다.
[2025-05-27 09:54:43,873: INFO/ForkPoolWorker-7] Task tasks.send_emails[7d7f9616-7b9b-4508-a889-95c35f54fe43] succeeded in 3.93334774998948s: {'result': 'All emails sent'} [2025-05-27 10:04:52,043: INFO/MainProcess] Task tasks.send_emails[ac2ec70f-2d3e-444a-95bb-185ac659f460] received [2025-05-27 10:04:52,046: WARNING/ForkPoolWorker-7] Sending email to <subscriber_email> [2025-05-27 10:04:53,474: WARNING/ForkPoolWorker-7] Email sent
newsletter 데이터베이스 의 deliveries 컬렉션 으로 이동하여 이메일 보냈는지 확인할 수도 있습니다.
다음 단계
이 애플리케이션 Flask 애플리케이션 셀러리 작업 대기열과 통합하여 구독자 데이터를 관리 하고 배치 이메일을 보내는 방법을 보여줍니다. 이 애플리케이션 기반으로 빌드 Flask 또는 셀러리를 실험해 볼 수 있습니다. 몇 가지 가능한 개선 사항에는 다음과 같은 변경 사항이 포함됩니다.
더 많은 리소스
이 튜토리얼에 사용된 구성 요소에 대한 자세한 내용은 다음 리소스를 참조하세요.
지원 찾거나 MongoDB Community 에 기여하려면 MongoDB 개발자 커뮤니티 페이지를 참조하세요.