From 9a348bca82c304bf853c8fe8496446928afae92f Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Wed, 14 May 2025 16:57:59 -0400 Subject: [PATCH 01/14] first draft --- snooty.toml | 3 +- source/integrations.txt | 4 + .../integrations/flask-celery-integration.txt | 171 ++++++++++++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 source/integrations/flask-celery-integration.txt diff --git a/snooty.toml b/snooty.toml index 125cb037..c888bf9c 100644 --- a/snooty.toml +++ b/snooty.toml @@ -12,7 +12,8 @@ toc_landing_pages = [ "/crud/query", "/crud/update", "/monitoring-and-logging", - "/reference" + "/reference", + "/integrations" ] intersphinx = [ diff --git a/source/integrations.txt b/source/integrations.txt index 41eb6a35..ba445c30 100644 --- a/source/integrations.txt +++ b/source/integrations.txt @@ -18,6 +18,10 @@ Third-Party Integrations and Tools .. meta:: :keywords: pypi, package, web, module, pip +.. toctree:: + + FastAPI Integration Tutorial + Overview -------- diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt new file mode 100644 index 00000000..f2b7a5e7 --- /dev/null +++ b/source/integrations/flask-celery-integration.txt @@ -0,0 +1,171 @@ +======================================================================== +Building a Scalable Newsletter Platform with Flask, MongoDB, and Celery +======================================================================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: flask, celery, integration, code example + +Overview +-------- + +In this tutorial, you can build a newsletter platform using Flask, MongoDB, and +Celery. This application allows users to subscribe to newsletters, and +administrators to manage and send batch emails asynchronously. + +Tutorial +-------- + +You can find the completed sample app for this tutorial in the :github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project ` GitHub repository. + +Prerequisites +~~~~~~~~~~~~~ + +Ensure you have the following components installed and set up before you start +this tutorial: + +- :ref:`MongoDB `: For data storage. +- `RabbitMQ `__: As the message broker for Celery. +- `Gmail `__: For sending emails via SMTP. +- `Python 3.8 or later `__ + +Set-up +~~~~~~ + + +.. procedure:: + :style: connected + + .. step:: Install the required Python packages. + + Run the following ``pip`` command in your terminal: + + .. code-block:: bash + + pip install Flask Flask-Mail pymongo celery + + .. step:: Create directory structure. + + We recommend structuring your application to separate concerns, which can + make the application modular and more maintainable. + + In your project directory, create the following directories and files: + + .. code-block:: none + + newsletter/ + ├── app.py + ├── config.py + ├── routes.py + ├── tasks.py + ├── templates/ + │ ├── admin.html + │ └── subscribe.html + ├── static/ + └── styles.css + +Configure Your Application +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In ``config.py``, define the necessary configurations by adding the following code: + +.. code-block:: python + + import os + + class Config: + CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' + RESULT_BACKEND = 'mongodb://localhost:27017/celery_results' + MAIL_SERVER = 'smtp.gmail.com' + MAIL_PORT = 587 + MAIL_USE_TLS = True + MAIL_USERNAME = os.getenv('MAIL_USERNAME') + MAIL_PASSWORD = os.getenv('MAIL_PASSWORD') + MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER') + ALLOWED_IPS = ['127.0.0.1'] + MONGO_URI = 'mongodb://localhost:27017/newsletter' + +Ensure that your Gmail credentials (``MAIL_USERNAME`` and ``MAIL_PASSWORD``) and +default sender email (``MAIL_DEFAULT_SENDER``) are set in your environment variables. + +Initialize Flask, MongoDB, and Celery +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In ``app.py``, initialize Flask, MongoDB, and Celery by adding the following code: + +.. code-block:: python + + from flask import Flask + from flask_mail import Mail + from pymongo import MongoClient + from celery import Celery + from config import Config + + app = Flask(__name__) + app.config.from_object(Config) + + mail = Mail(app) + client = MongoClient(app.config['MONGO_URI']) + db = client.get_database() + + celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) + celery.conf.update(app.config) + + from routes import * + from tasks import * + +Define Your Routes +~~~~~~~~~~~~~~~~~~ + +In ``routes.py``, define the necessary routes by adding the following code: + +.. code-block:: python + + from flask import render_template, request, jsonify, abort + from app import app, db + from tasks import send_emails + + @app.before_request + 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) + + @app.route('/') + def home(): + return render_template('subscribe.html') + + @app.route('/admin') + def admin(): + return render_template('admin.html') + + @app.route('/subscribe', methods=['POST']) + def subscribe(): + email = request.form['email'] + if db.users.find_one({'email': email}): + +After you complete these steps, you have a working application that +uses MongoDB, Flask and Celery to manage a newsletter system. + +More Resources +-------------- + +For more information about Flask and Celery integration, see the following +resources: + +- `Flask `__ +- `Flask Mail `__ +- `Celery `__ \ No newline at end of file From e30f29156e4d01f5be52373d9c99358ca6679d88 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Thu, 15 May 2025 12:33:12 -0400 Subject: [PATCH 02/14] edits --- .../integrations/celery-admin-page.png | Bin 0 -> 50794 bytes .../integrations/celery-subscriber-page.png | Bin 0 -> 75263 bytes source/integrations.txt | 2 +- .../integrations/flask-celery-integration.txt | 130 +++++++++++++++--- 4 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 source/includes/integrations/celery-admin-page.png create mode 100644 source/includes/integrations/celery-subscriber-page.png diff --git a/source/includes/integrations/celery-admin-page.png b/source/includes/integrations/celery-admin-page.png new file mode 100644 index 0000000000000000000000000000000000000000..a397b115fc85275dfecc08656e04b7c0a6e6ed1c GIT binary patch literal 50794 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 literal 0 HcmV?d00001 diff --git a/source/includes/integrations/celery-subscriber-page.png b/source/includes/integrations/celery-subscriber-page.png new file mode 100644 index 0000000000000000000000000000000000000000..d2338c76b8f24e41810818d3cceb2569714d3368 GIT binary patch literal 75263 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 + Tutorial: Flask and Celery Integration Overview -------- diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index f2b7a5e7..d109397d 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -1,6 +1,6 @@ -======================================================================== -Building a Scalable Newsletter Platform with Flask, MongoDB, and Celery -======================================================================== +====================================== +Tutorial: Flask and Celery Integration +====================================== .. contents:: On this page :local: @@ -33,21 +33,28 @@ Prerequisites Ensure you have the following components installed and set up before you start this tutorial: -- :ref:`MongoDB `: For data storage. -- `RabbitMQ `__: As the message broker for Celery. -- `Gmail `__: For sending emails via SMTP. +- :ref:`MongoDB ` +- `RabbitMQ `__ (message broker for Celery) +- `Gmail `__ (to use as an SMTP) - `Python 3.8 or later `__ Set-up ~~~~~~ - .. procedure:: :style: connected .. step:: Install the required Python packages. + + Your application depends on the following libraries: + + - `Flask `__ for handling the web server and routing + - `Flask Mail `__ for sending emails from your application + - :ref:`{+driver-long+} ` + - `Celery `__ to manage tasks, such + as sending batch emails - Run the following ``pip`` command in your terminal: + Run the following ``pip`` command in your terminal to install the dependencies: .. code-block:: bash @@ -58,7 +65,7 @@ Set-up We recommend structuring your application to separate concerns, which can make the application modular and more maintainable. - In your project directory, create the following directories and files: + In your project directory, create the following structure: .. code-block:: none @@ -76,7 +83,8 @@ Set-up Configure Your Application ~~~~~~~~~~~~~~~~~~~~~~~~~~ -In ``config.py``, define the necessary configurations by adding the following code: +Define the necessary configurations by adding the following code to your +``config.py`` file: .. code-block:: python @@ -100,7 +108,8 @@ default sender email (``MAIL_DEFAULT_SENDER``) are set in your environment varia Initialize Flask, MongoDB, and Celery ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In ``app.py``, initialize Flask, MongoDB, and Celery by adding the following code: +Initialize Flask, MongoDB, and Celery by adding the following code to your +``app.py`` file: .. code-block:: python @@ -123,10 +132,17 @@ In ``app.py``, initialize Flask, MongoDB, and Celery by adding the following cod from routes import * from tasks import * +Ensure that your connection string (``MONGOD_URI``) and broker url +(``CELERY_BROKER_URL``) are set in your environment variables. For more in +formation see the :ref:`Create a Connection String +` section of this guide and the `Broker Settings +`__ +section of the Celery documentation. + Define Your Routes ~~~~~~~~~~~~~~~~~~ -In ``routes.py``, define the necessary routes by adding the following code: +Define the necessary routes by adding the following code to your ``routes.py`` file: .. code-block:: python @@ -157,15 +173,97 @@ In ``routes.py``, define the necessary routes by adding the following code: email = request.form['email'] if db.users.find_one({'email': email}): -After you complete these steps, you have a working application that -uses MongoDB, Flask and Celery to manage a newsletter system. +After you complete these steps, you will have a working application that +uses MongoDB, Flask and Celery to manage a newsletter platform. + +Testing the Platform +~~~~~~~~~~~~~~~~~~~~ + +To test your application, run the following ``flask`` command in the terminal: + +.. procedure:: + :style: connected + + .. step:: Start Your Application + + .. code-block:: bash + + flask --app app run + + In another terminal, start the celery worker: + + .. code-block:: bash + + celery -A app.celery worker --loglevel=info + + .. step:: Create a Subscriber + + Navigate to ``localhost:5000`` in your browser to open the + :guilabel:`Subscribe to our Newsletter` page. The following image shows + the subscriber webpage: + + .. image:: /includes/integrations/celery-subscriber-page.png + :alt: Screenshot of browser and subscriber page + + Enter the subscriber information and click :guilabel:`Subscribe`. + + To confirm that you created a new subscriber, run the following code in + your terminal to open a MongoDB Shell instance and view your collections: + + .. code-block:: shell + + mongosh + show dbs + use newsletter + show collections + + .. step:: Dispatch a Newsletter + + Navigate to ``localhost:5000/admin`` in your browser to open the + :guilabel:`Send Newsletter` page. The following image shows the admin + webpage: + + .. image:: /includes/integrations/celery-admin-page.png + :alt: Screenshot of browser and admin + + Enter the newsletter details and click :guilabel:`Send`. + + Your Celery worker log should display an ``Email sent`` log entry, as + shown in the following image: + + .. code-block:: bash + + [2024-06-06 13:34:37,304: WARNING/ForkPoolWorker-4] Email sent + [2024-06-06 13:34:37,305: INFO/ForkPoolWorker-4] Task tasks.send_emails[b119bb9e-b2ef-4c85-b048-ca96e0e60ae1] succeeded in 17.155154566993588s: {'result': 'All emails sent'} + + You can also see your newsletter deliverable by running the following + command in your MongoDB Shell to review your collections: + + .. code-block:: shell + + newsletter> show collections + deliveries + subscribers + newsletter> + + .. step:: Review Your Sent Newsletter + + Run the following commands in your MongoDB Shell to your previously sent + newsletters, also called ``deliveries``: + + .. code-block:: shell + + db.deliveries.find().pretty() More Resources -------------- -For more information about Flask and Celery integration, see the following +For more information about to components used in this tutorial, see the following resources: - `Flask `__ - `Flask Mail `__ -- `Celery `__ \ No newline at end of file +- `Celery `__ +- :mdb-shell:`MongoDB Shell <>` + +For support or to contribute to the MongoDB Community, see the `MongoDB Developer Community `__. \ No newline at end of file From adac78ddc2f4de567a1fd19a8b7b2b4cced76acc Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Thu, 15 May 2025 13:49:11 -0400 Subject: [PATCH 03/14] vale --- source/integrations/flask-celery-integration.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index d109397d..8bd739dc 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -228,7 +228,7 @@ To test your application, run the following ``flask`` command in the terminal: Enter the newsletter details and click :guilabel:`Send`. - Your Celery worker log should display an ``Email sent`` log entry, as + Your Celery worker log will display an ``Email sent`` log entry, as shown in the following image: .. code-block:: bash From 605d9d417e166d8984c6ae6306585f61ce8214c2 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Thu, 15 May 2025 13:51:34 -0400 Subject: [PATCH 04/14] next steps --- source/integrations/flask-celery-integration.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index 8bd739dc..e5916bf2 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -255,6 +255,14 @@ To test your application, run the following ``flask`` command in the terminal: db.deliveries.find().pretty() +Next Steps +~~~~~~~~~~ + +This application demonstrates how to handle asynchronous tasks efficiently, +manage subscriber data, and send batch emails. You can further enhance this +platform by integrating analytics, customizing email templates, and implementing +automated responses. + More Resources -------------- From ea5fc4995209372edc69b471016253e4d3e06816 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Tue, 27 May 2025 12:07:16 -0400 Subject: [PATCH 05/14] update --- .../integrations/celery-admin-page.png | Bin 50794 -> 0 bytes .../integrations/celery-subscriber-page.png | Bin 75263 -> 0 bytes .../integrations/flask-celery-integration.txt | 498 ++++++++++++++---- 3 files changed, 391 insertions(+), 107 deletions(-) delete mode 100644 source/includes/integrations/celery-admin-page.png delete mode 100644 source/includes/integrations/celery-subscriber-page.png diff --git a/source/includes/integrations/celery-admin-page.png b/source/includes/integrations/celery-admin-page.png deleted file mode 100644 index a397b115fc85275dfecc08656e04b7c0a6e6ed1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50794 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 diff --git a/source/includes/integrations/celery-subscriber-page.png b/source/includes/integrations/celery-subscriber-page.png deleted file mode 100644 index d2338c76b8f24e41810818d3cceb2569714d3368..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75263 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. + +Flask +~~~~~ + +Flask is a lightweight web application framework with built-in configuration and +convention defaults that provide consistency to developers across projects. For +more information, see the `Flask webpage +`__. Tutorial -------- -You can find the completed sample app for this tutorial in the :github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project ` GitHub repository. +This tutorial creates a modified version of the sample application in the +:github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project +` GitHub repository. Prerequisites ~~~~~~~~~~~~~ @@ -33,7 +54,12 @@ Prerequisites Ensure you have the following components installed and set up before you start this tutorial: -- :ref:`MongoDB ` +- A MongoDB Cluster. We recommend setting up a cluster using Atlas. See the + :atlas:`Get Started with Atlas ` page + in the Atlas documentation. +- A database in your cluster called ``newsletter``. For more information, see + the :atlas:`Create a Database ` page + in the Atlas guide. - `RabbitMQ `__ (message broker for Celery) - `Gmail `__ (to use as an SMTP) - `Python 3.8 or later `__ @@ -44,26 +70,24 @@ Set-up .. procedure:: :style: connected - .. step:: Install the required Python packages. - - Your application depends on the following libraries: - - - `Flask `__ for handling the web server and routing - - `Flask Mail `__ for sending emails from your application - - :ref:`{+driver-long+} ` - - `Celery `__ to manage tasks, such - as sending batch emails - - Run the following ``pip`` command in your terminal to install the dependencies: + .. step:: Create your project directory and structure. + + The ``newsletter`` directory your the project directory for this tutorial. You can open .. code-block:: bash - pip install Flask Flask-Mail pymongo celery + mkdir newsletter + cd newsletter - .. step:: Create directory structure. + - ``app.py``: The main entry point for your Flask application. + - ``config.py``: Configuration settings for your application, including + MongoDB connection details, mail server configuration, Celery broker + connection, and any other environment-specific variables. + - ``tasks.py``: Defines background tasks to send emails asynchronously. + - ``routes.py``: Define the routes (URLs) that your application responds to. We recommend structuring your application to separate concerns, which can - make the application modular and more maintainable. + make the application modular and more maintainable. In your project directory, create the following structure: @@ -77,12 +101,42 @@ Set-up ├── templates/ │ ├── admin.html │ └── subscribe.html - ├── static/ - └── styles.css + └── static/ + └── styles.css + + .. step:: Install the required Python packages. + + Your application depends on the following libraries: + + - `Flask `__ for handling the web server and routing + - `Flask Mail `__ for sending emails from your application + - :ref:`{+driver-short+} ` + - `Celery `__ to manage tasks, such + as sending batch emails + + .. tip:: Use a Virtual environment + + Installing your Python dependencies in a `virtualenv + `__ allows you to install + versions of your libraries for individual projects. Before running any + ``pip`` commands, ensure your ``virtualenv`` is active. + + Run the following ``pip`` command in your terminal to install the dependencies: + + .. code-block:: bash + + pip install Flask Flask-Mail pymongo celery Configure Your Application ~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``config.py`` file contains the settings and credentials to perform the +following actions: + +- Connect Celery to RabbitMQ as its message broker +- Configure Flask-Mail to use Gmail as its SMPT server +- Connect your application to your MongoDB server + Define the necessary configurations by adding the following code to your ``config.py`` file: @@ -91,19 +145,31 @@ Define the necessary configurations by adding the following code to your import os class Config: - CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' - RESULT_BACKEND = 'mongodb://localhost:27017/celery_results' - MAIL_SERVER = 'smtp.gmail.com' - MAIL_PORT = 587 - MAIL_USE_TLS = True - MAIL_USERNAME = os.getenv('MAIL_USERNAME') - MAIL_PASSWORD = os.getenv('MAIL_PASSWORD') - MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER') - ALLOWED_IPS = ['127.0.0.1'] - MONGO_URI = 'mongodb://localhost:27017/newsletter' - -Ensure that your Gmail credentials (``MAIL_USERNAME`` and ``MAIL_PASSWORD``) and -default sender email (``MAIL_DEFAULT_SENDER``) are set in your environment variables. + MAIL_SERVER = 'smtp.gmail.com' + MAIL_PORT = 587 + MAIL_USE_TLS = True + MAIL_USERNAME = '' # Your email address without the domain, i.e. without '@gmail.com' + MAIL_PASSWORD = '' + ALLOWED_IPS = ['127.0.0.1'] + MONGO_URI = '' + CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' + RESULT_BACKEND = MONGO_URI + '/celery_results' + +You must provide your Gmail credentials (``MAIL_USERNAME`` and ``MAIL_PASSWORD``) to +enable your application to send emails. For security purposes, we recommend that +you generate an app password to use, rather than using your primary password. +For more information, see the `App Password settings +`__ in your Google Account. + +You must also create a connection string (``MONGO_URI``) are set in your +environment variables. For more information see the :ref:`Create a Connection +String ` section of this guide + +The provided broker url (``CELERY_BROKER_URL``) using RabbitMQ as the broker, +but you can customize this url to support other implementations. For more +information, see the `Broker Settings +`__ +section of the Celery documentation. Initialize Flask, MongoDB, and Celery ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -117,14 +183,13 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your from flask_mail import Mail from pymongo import MongoClient from celery import Celery - from config import Config app = Flask(__name__) - app.config.from_object(Config) + app.config.from_object('config.Config') mail = Mail(app) client = MongoClient(app.config['MONGO_URI']) - db = client.get_database() + db = client.get_database(name="newsletter") celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) celery.conf.update(app.config) @@ -132,133 +197,352 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your from routes import * from tasks import * -Ensure that your connection string (``MONGOD_URI``) and broker url -(``CELERY_BROKER_URL``) are set in your environment variables. For more in -formation see the :ref:`Create a Connection String -` section of this guide and the `Broker Settings -`__ -section of the Celery documentation. + if __name__ == '__main__': + app.run(debug=True) + +This opens a connection to the ``newsletter`` database in your MongoDB cluster, +and configures your Celery task queue. Define Your Routes ~~~~~~~~~~~~~~~~~~ -Define the necessary routes by adding the following code to your ``routes.py`` file: +Define the root, admin, subscribe and send-newsletter routes by adding the following code to your ``routes.py`` file: .. code-block:: python - from flask import render_template, request, jsonify, abort + from flask import render_template, request, abort, jsonify from app import app, db from tasks import send_emails @app.before_request 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) + 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) @app.route('/') def home(): - return render_template('subscribe.html') + return render_template('subscribe.html') @app.route('/admin') def admin(): - return render_template('admin.html') + return render_template('admin.html') @app.route('/subscribe', methods=['POST']) def subscribe(): - email = request.form['email'] - if db.users.find_one({'email': email}): - -After you complete these steps, you will have a working application that -uses MongoDB, Flask and Celery to manage a newsletter platform. + first_name = request.form['firstname'] + last_name = request.form['lastname'] + email = request.form['email'] + + if db.users.find_one({'email': email}): + return """ +

+ This email is already subscribed! +
+ """, 409 + + db.users.insert_one({'firstname': first_name, 'lastname': last_name, 'email': email, 'subscribed': True}) + return """ +
+ Subscribed successfully! +
+ """, 200 + + @app.route('/send-newsletters', methods=['POST']) + 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 + +You can add more security protections or customize user-facing alerts for your +application in this file. + +Create Your Pages +~~~~~~~~~~~~~~~~~ + +In the ``templates`` directory you can build your user interface. + +Copy the following code into your ``subscribe.html`` file: + +.. code-block:: html + + + + + + + Subscribe to Newsletter + + + +

Subscribe to our Newsletter

+
+ + +
+ + +
+ + +
+ +
+
+ + + + +Because this application uses asynchronous messages, the script in this file +uses Fetch API calls. This script also handles timeouts and errors. + +Copy the following code into your ``admin.html`` file: + +.. code-block:: html + + + + + + + Admin - Send Newsletter + + + +

Send Newsletter

+
+ + +
+ + +
+ +
+
+ + + + +The script in this file also used Fetch for asynchronous calls. It also displays +an alert to the user which depends on the success of the ``send_newsletter`` +call. + +Format Your Pages +~~~~~~~~~~~~~~~~~ + +You can apply a style sheet to your templates by adding the following code to +the ``styles.css`` file: + +.. code-block:: 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; + } + +You can modify this style sheet or create your own to customize your +application. Testing the Platform ~~~~~~~~~~~~~~~~~~~~ -To test your application, run the following ``flask`` command in the terminal: +After you complete the previous steps, you have a working application that +uses MongoDB, Flask and Celery to manage a newsletter platform. + +You can use the following steps to test your application: .. procedure:: :style: connected - .. step:: Start Your Application + .. step:: Start your background services. + + Start your RabbitMQ node by running the following code: + + .. code-block:: bash + + brew services start rabbitmq + + .. step:: Start your application. + + Use the following code to start your application: .. code-block:: bash flask --app app run - In another terminal, start the celery worker: + In another terminal, start the Celery worker: .. code-block:: bash celery -A app.celery worker --loglevel=info - .. step:: Create a Subscriber + .. step:: Create a subscriber. Navigate to ``localhost:5000`` in your browser to open the - :guilabel:`Subscribe to our Newsletter` page. The following image shows - the subscriber webpage: - - .. image:: /includes/integrations/celery-subscriber-page.png - :alt: Screenshot of browser and subscriber page + :guilabel:`Subscribe to our Newsletter` page. Enter the subscriber information and click :guilabel:`Subscribe`. - To confirm that you created a new subscriber, run the following code in - your terminal to open a MongoDB Shell instance and view your collections: - - .. code-block:: shell - - mongosh - show dbs - use newsletter - show collections + To confirm that you created a new subscriber, open `Atlas + `__ and navigate to the + ``users`` collection in your ``newletter`` database. - .. step:: Dispatch a Newsletter + .. step:: Dispatch a newsletter. Navigate to ``localhost:5000/admin`` in your browser to open the - :guilabel:`Send Newsletter` page. The following image shows the admin - webpage: - - .. image:: /includes/integrations/celery-admin-page.png - :alt: Screenshot of browser and admin - - Enter the newsletter details and click :guilabel:`Send`. + :guilabel:`Send Newsletter` page. Enter the newsletter details and click + :guilabel:`Send`. Your Celery worker log will display an ``Email sent`` log entry, as shown in the following image: .. code-block:: bash - [2024-06-06 13:34:37,304: WARNING/ForkPoolWorker-4] Email sent - [2024-06-06 13:34:37,305: INFO/ForkPoolWorker-4] Task tasks.send_emails[b119bb9e-b2ef-4c85-b048-ca96e0e60ae1] succeeded in 17.155154566993588s: {'result': 'All emails sent'} - - You can also see your newsletter deliverable by running the following - command in your MongoDB Shell to review your collections: - - .. code-block:: shell - - newsletter> show collections - deliveries - subscribers - newsletter> - - .. step:: Review Your Sent Newsletter - - Run the following commands in your MongoDB Shell to your previously sent - newsletters, also called ``deliveries``: - - .. code-block:: shell + [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 + [2025-05-27 10:04:53,474: WARNING/ForkPoolWorker-7] Email sent - db.deliveries.find().pretty() + You can also confirm that you sent an email navigating to the + ``deliveries`` collection in your ``newletter`` database. Next Steps ~~~~~~~~~~ -This application demonstrates how to handle asynchronous tasks efficiently, +This application demonstrates how to integrate with the Celery tasks task queue to manage subscriber data, and send batch emails. You can further enhance this platform by integrating analytics, customizing email templates, and implementing automated responses. From 60c52fdbc0881a30acb9dc6b695c1085d54d21b2 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Tue, 27 May 2025 12:10:57 -0400 Subject: [PATCH 06/14] vale --- source/integrations/flask-celery-integration.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index eabfe365..82b48040 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -22,7 +22,7 @@ Overview -------- In this tutorial, you can learn how to build a newsletter platform using -MongoDB, Celery and Flask. This application allows users to subscribe to +MongoDB, Celery, and Flask. This application allows users to subscribe to newsletters, and administrators to manage and send batch emails asynchronously. Celery @@ -148,7 +148,7 @@ Define the necessary configurations by adding the following code to your MAIL_SERVER = 'smtp.gmail.com' MAIL_PORT = 587 MAIL_USE_TLS = True - MAIL_USERNAME = '' # Your email address without the domain, i.e. without '@gmail.com' + MAIL_USERNAME = '' # Your email address without the domain, that is without '@gmail.com' MAIL_PASSWORD = '' ALLOWED_IPS = ['127.0.0.1'] MONGO_URI = '' @@ -206,7 +206,7 @@ and configures your Celery task queue. Define Your Routes ~~~~~~~~~~~~~~~~~~ -Define the root, admin, subscribe and send-newsletter routes by adding the following code to your ``routes.py`` file: +Define the root, admin, subscribe, and send-newsletter routes by adding the following code to your ``routes.py`` file: .. code-block:: python From d0ec74280645e77a947d9f48584f3757b2d73a84 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Wed, 4 Jun 2025 11:22:13 -0400 Subject: [PATCH 07/14] MW feedback --- .../integrations/flask-celery-integration.txt | 126 +++++++++--------- 1 file changed, 66 insertions(+), 60 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index 82b48040..720a12fc 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -16,19 +16,19 @@ Tutorial: Celery and Flask Integration :values: tutorial .. meta:: - :keywords: flask, celery, integration, code example + :keywords: code example, batch, framework Overview -------- -In this tutorial, you can learn how to build a newsletter platform using -MongoDB, Celery, and Flask. This application allows users to subscribe to +In this tutorial, you can learn how to use MongoDB, Celery, and Flask +to build a newsletter platform. This application allows users to subscribe to newsletters, and administrators to manage and send batch emails asynchronously. Celery ~~~~~~ -Celery is an open-source distributed task queue that makes handling large +Celery is an open-source distributed task queue that handles large volumes of messages efficiently. It supports asynchronous processing and task scheduling. For more information, see the `Celery webpage `__. @@ -51,40 +51,45 @@ This tutorial creates a modified version of the sample application in the Prerequisites ~~~~~~~~~~~~~ -Ensure you have the following components installed and set up before you start +Ensure that you have the following components installed and set up before you start this tutorial: -- A MongoDB Cluster. We recommend setting up a cluster using Atlas. See the +- A MongoDB cluster. We recommend that you use Atlas. To learn how + to create an Atlas cluster, see the :atlas:`Get Started with Atlas ` page in the Atlas documentation. -- A database in your cluster called ``newsletter``. For more information, see +- A database names ``newsletter`` in your cluster. For more information, see the :atlas:`Create a Database ` page in the Atlas guide. -- `RabbitMQ `__ (message broker for Celery) -- `Gmail `__ (to use as an SMTP) +- `RabbitMQ `__ to use as a message broker for Celery. +- `Gmail `__ to use as an SMTP server. For more information about + SMTP servers, see the `Simple Mail Transfer Protocol + `__ wikipedia page. - `Python 3.8 or later `__ -Set-up -~~~~~~ +Setup +~~~~~ .. procedure:: :style: connected - .. step:: Create your project directory and structure. + .. step:: Create your project directory and structure - The ``newsletter`` directory your the project directory for this tutorial. You can open + The name of your project directory is ``newsletter``. Create your directory and navigate to it by running the following commands in terminal: .. code-block:: bash mkdir newsletter cd newsletter + + The following files will hold the code for your application: - - ``app.py``: The main entry point for your Flask application. + - ``app.py``: The main entry point for your Flask application - ``config.py``: Configuration settings for your application, including MongoDB connection details, mail server configuration, Celery broker - connection, and any other environment-specific variables. - - ``tasks.py``: Defines background tasks to send emails asynchronously. - - ``routes.py``: Define the routes (URLs) that your application responds to. + connection, and any other environment-specific variables + - ``tasks.py``: Defines background tasks to send emails asynchronously + - ``routes.py``: Defines the routes (URLs) that your application responds to We recommend structuring your application to separate concerns, which can make the application modular and more maintainable. @@ -104,7 +109,7 @@ Set-up └── static/ └── styles.css - .. step:: Install the required Python packages. + .. step:: Install the required Python packages Your application depends on the following libraries: @@ -114,12 +119,12 @@ Set-up - `Celery `__ to manage tasks, such as sending batch emails - .. tip:: Use a Virtual environment + .. tip:: Use a Virtual Environment - Installing your Python dependencies in a `virtualenv - `__ allows you to install - versions of your libraries for individual projects. Before running any - ``pip`` commands, ensure your ``virtualenv`` is active. + Python `virtual environments + `__ allow you to install + different versions of libraries for different projects. Before running + any ``pip`` commands, ensure that your ``virtualenv`` is active. Run the following ``pip`` command in your terminal to install the dependencies: @@ -134,7 +139,7 @@ The ``config.py`` file contains the settings and credentials to perform the following actions: - Connect Celery to RabbitMQ as its message broker -- Configure Flask-Mail to use Gmail as its SMPT server +- Configure Flask-Mail to use Gmail as its SMTP server - Connect your application to your MongoDB server Define the necessary configurations by adding the following code to your @@ -148,10 +153,10 @@ Define the necessary configurations by adding the following code to your MAIL_SERVER = 'smtp.gmail.com' MAIL_PORT = 587 MAIL_USE_TLS = True - MAIL_USERNAME = '' # Your email address without the domain, that is without '@gmail.com' + MAIL_USERNAME = '' # Your email address without '@gmail.com' MAIL_PASSWORD = '' ALLOWED_IPS = ['127.0.0.1'] - MONGO_URI = '' + MONGO_URI = '' CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' RESULT_BACKEND = MONGO_URI + '/celery_results' @@ -161,12 +166,12 @@ you generate an app password to use, rather than using your primary password. For more information, see the `App Password settings `__ in your Google Account. -You must also create a connection string (``MONGO_URI``) are set in your -environment variables. For more information see the :ref:`Create a Connection -String ` section of this guide +You must also create a connection string to set into the ``MONGO_URI`` +environment variable. For more information see the :ref:`Create a Connection +String ` section of this guide. -The provided broker url (``CELERY_BROKER_URL``) using RabbitMQ as the broker, -but you can customize this url to support other implementations. For more +The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its broker, +but you can customize this URL to support other implementations. For more information, see the `Broker Settings `__ section of the Celery documentation. @@ -200,13 +205,13 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your if __name__ == '__main__': app.run(debug=True) -This opens a connection to the ``newsletter`` database in your MongoDB cluster, +This opens a connection to the ``newsletter`` database in your MongoDB cluster and configures your Celery task queue. Define Your Routes ~~~~~~~~~~~~~~~~~~ -Define the root, admin, subscribe, and send-newsletter routes by adding the following code to your ``routes.py`` file: +Define the ``root``, ``admin``, ``subscribe``, and ``send-newsletter`` routes by adding the following code to your ``routes.py`` file: .. code-block:: python @@ -270,9 +275,15 @@ application in this file. Create Your Pages ~~~~~~~~~~~~~~~~~ -In the ``templates`` directory you can build your user interface. +You can build your user interface in the ``templates`` directory. + +Because this application uses asynchronous messages, the scripts in the +following files use `Fetch API calls +`__. They also +handle timeouts and errors. -Copy the following code into your ``subscribe.html`` file: +Copy the following code into your ``subscribe.html`` file to create your +:guilabel:`Subscribe to Newsletter` page. .. code-block:: html @@ -330,10 +341,11 @@ Copy the following code into your ``subscribe.html`` file: -Because this application uses asynchronous messages, the script in this file -uses Fetch API calls. This script also handles timeouts and errors. +The script for the admin page displays an alert to the user which depends on the +success of the ``send_newsletter`` call. -Copy the following code into your ``admin.html`` file: +Copy the following code into your ``admin.html`` file to create your +:guilabel:`Send Newsletter` page: .. code-block:: html @@ -385,10 +397,6 @@ Copy the following code into your ``admin.html`` file: -The script in this file also used Fetch for asynchronous calls. It also displays -an alert to the user which depends on the success of the ``send_newsletter`` -call. - Format Your Pages ~~~~~~~~~~~~~~~~~ @@ -480,22 +488,20 @@ Testing the Platform ~~~~~~~~~~~~~~~~~~~~ After you complete the previous steps, you have a working application that -uses MongoDB, Flask and Celery to manage a newsletter platform. +uses MongoDB, Flask, and Celery to manage a newsletter platform. You can use the following steps to test your application: .. procedure:: :style: connected - .. step:: Start your background services. - - Start your RabbitMQ node by running the following code: - - .. code-block:: bash + .. step:: Start your background services - brew services start rabbitmq + Start your RabbitMQ node. For instructions, see the `RabbitMQ + documentation `__ for your + operating system. - .. step:: Start your application. + .. step:: Start your application Use the following code to start your application: @@ -509,7 +515,7 @@ You can use the following steps to test your application: celery -A app.celery worker --loglevel=info - .. step:: Create a subscriber. + .. step:: Create a subscriber Navigate to ``localhost:5000`` in your browser to open the :guilabel:`Subscribe to our Newsletter` page. @@ -520,14 +526,14 @@ You can use the following steps to test your application: `__ and navigate to the ``users`` collection in your ``newletter`` database. - .. step:: Dispatch a newsletter. + .. step:: Dispatch a newsletter Navigate to ``localhost:5000/admin`` in your browser to open the :guilabel:`Send Newsletter` page. Enter the newsletter details and click :guilabel:`Send`. - Your Celery worker log will display an ``Email sent`` log entry, as - shown in the following image: + Your Celery worker log will display an ``Email sent`` log entry similar to + the following image: .. code-block:: bash @@ -536,13 +542,13 @@ You can use the following steps to test your application: [2025-05-27 10:04:52,046: WARNING/ForkPoolWorker-7] Sending email to [2025-05-27 10:04:53,474: WARNING/ForkPoolWorker-7] Email sent - You can also confirm that you sent an email navigating to the - ``deliveries`` collection in your ``newletter`` database. + You can also confirm that you sent an email by navigating to the + ``deliveries`` collection in your ``newsletter`` database. Next Steps ~~~~~~~~~~ -This application demonstrates how to integrate with the Celery tasks task queue to +This application demonstrates how to integrate with the Celery task queue to manage subscriber data, and send batch emails. You can further enhance this platform by integrating analytics, customizing email templates, and implementing automated responses. @@ -550,12 +556,12 @@ automated responses. More Resources -------------- -For more information about to components used in this tutorial, see the following +For more information about the components used in this tutorial, see the following resources: - `Flask `__ - `Flask Mail `__ - `Celery `__ -- :mdb-shell:`MongoDB Shell <>` +- `RabbitMQ `__ -For support or to contribute to the MongoDB Community, see the `MongoDB Developer Community `__. \ No newline at end of file +To find support or to contribute to the MongoDB community, see the `MongoDB Developer Community `__ page. \ No newline at end of file From 0aac3a1dbc93b19da71ff0e50d2fdb68db467261 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Thu, 5 Jun 2025 12:04:42 -0400 Subject: [PATCH 08/14] MW feedback --- source/integrations/flask-celery-integration.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index 720a12fc..cde335e4 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -58,13 +58,13 @@ this tutorial: to create an Atlas cluster, see the :atlas:`Get Started with Atlas ` page in the Atlas documentation. -- A database names ``newsletter`` in your cluster. For more information, see +- A database named ``newsletter`` in your cluster. For more information, see the :atlas:`Create a Database ` page in the Atlas guide. - `RabbitMQ `__ to use as a message broker for Celery. - `Gmail `__ to use as an SMTP server. For more information about - SMTP servers, see the `Simple Mail Transfer Protocol - `__ wikipedia page. + SMTP servers, see the :wikipedia:`Simple Mail Transfer Protocol + ` Wikipedia page. - `Python 3.8 or later `__ Setup @@ -278,8 +278,7 @@ Create Your Pages You can build your user interface in the ``templates`` directory. Because this application uses asynchronous messages, the scripts in the -following files use `Fetch API calls -`__. They also +following files use :wikipedia:`Fetch API calls `. They also handle timeouts and errors. Copy the following code into your ``subscribe.html`` file to create your @@ -341,7 +340,7 @@ Copy the following code into your ``subscribe.html`` file to create your -The script for the admin page displays an alert to the user which depends on the +The script for the admin page displays an alert to the user that depends on the success of the ``send_newsletter`` call. Copy the following code into your ``admin.html`` file to create your From ca29f64af36e971545c63f3675a07cda43489eda Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Wed, 18 Jun 2025 21:53:48 -0400 Subject: [PATCH 09/14] descriptions --- .../integrations/flask-celery-integration.txt | 140 +++++++++++------- 1 file changed, 86 insertions(+), 54 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index cde335e4..c2c2d277 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -2,7 +2,7 @@ .. original URL: https://www.mongodb.com/developer/products/mongodb/python-flask-celery-newsletter/ ====================================== -Tutorial: Celery and Flask Integration +Tutorial: Flask and Celery Integration ====================================== .. contents:: On this page @@ -21,38 +21,29 @@ Tutorial: Celery and Flask Integration Overview -------- -In this tutorial, you can learn how to use MongoDB, Celery, and Flask -to build a newsletter platform. This application allows users to subscribe to -newsletters, and administrators to manage and send batch emails asynchronously. - -Celery -~~~~~~ - -Celery is an open-source distributed task queue that handles large -volumes of messages efficiently. It supports asynchronous processing and task -scheduling. For more information, see the `Celery webpage -`__. +In this tutorial, you can learn how to use MongoDB, Flask, and Celery to build a newsletter platform. This application allows users to subscribe to newsletters, and administrators to manage and send batch emails asynchronously. Flask ~~~~~ Flask is a lightweight web application framework with built-in configuration and convention defaults that provide consistency to developers across projects. For -more information, see the `Flask webpage -`__. +more information, see the `Flask webpage `__. + +Celery +~~~~~~ + +Celery is an open-source distributed task queue that handles large volumes of messages efficiently. It supports asynchronous processing and task scheduling. For more information, see the `Celery webpage `__. Tutorial -------- -This tutorial creates a modified version of the sample application in the -:github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project -` GitHub repository. +This tutorial creates a modified version of the sample application in the :github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project ` GitHub repository. Prerequisites ~~~~~~~~~~~~~ -Ensure that you have the following components installed and set up before you start -this tutorial: +Ensure that you have the following components installed and set up before you start this tutorial: - A MongoDB cluster. We recommend that you use Atlas. To learn how to create an Atlas cluster, see the @@ -65,7 +56,7 @@ this tutorial: - `Gmail `__ to use as an SMTP server. For more information about SMTP servers, see the :wikipedia:`Simple Mail Transfer Protocol ` Wikipedia page. -- `Python 3.8 or later `__ +- `Python 3.9 or later `__ Setup ~~~~~ @@ -130,20 +121,18 @@ Setup .. code-block:: bash - pip install Flask Flask-Mail pymongo celery + pip install flask-pymongo Flask-Mail celery Configure Your Application ~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``config.py`` file contains the settings and credentials to perform the -following actions: +The ``config.py`` file contains the settings and credentials to perform the following actions: - Connect Celery to RabbitMQ as its message broker - Configure Flask-Mail to use Gmail as its SMTP server - Connect your application to your MongoDB server -Define the necessary configurations by adding the following code to your -``config.py`` file: +Define the necessary configurations by adding the following code to your ``config.py`` file: .. code-block:: python @@ -160,25 +149,22 @@ Define the necessary configurations by adding the following code to your CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' RESULT_BACKEND = MONGO_URI + '/celery_results' -You must provide your Gmail credentials (``MAIL_USERNAME`` and ``MAIL_PASSWORD``) to -enable your application to send emails. For security purposes, we recommend that -you generate an app password to use, rather than using your primary password. -For more information, see the `App Password settings -`__ in your Google Account. +You must provide your Gmail credentials (``MAIL_USERNAME`` and ``MAIL_PASSWORD``) to enable your application to send emails. For security purposes, we recommend that you generate an app password to use, rather than using your primary password. For more information, see the `App Password settings `__ in your Google Account. -You must also create a connection string to set into the ``MONGO_URI`` -environment variable. For more information see the :ref:`Create a Connection -String ` section of this guide. +You must also create a connection string to set into the ``MONGO_URI`` environment variable. For more information see the :ref:`Create a Connection String ` section of this guide. -The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its broker, -but you can customize this URL to support other implementations. For more -information, see the `Broker Settings -`__ -section of the Celery documentation. +The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its broker, but you can customize this URL to support other implementations. For more information, see the `Broker Settings `__ section of the Celery documentation. Initialize Flask, MongoDB, and Celery ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``app.py`` file initializes and configures the core components of the Flask application. It performs the following tasks: + +- Creates a Flask application and loads configuration constants +- Initializes a Flask-Mail instance with the app's mail server settings +- Connects to the ``newsletter`` MongoDB database by using the {+driver-short+} driver +- Creates a Celery instance configured with the Flask app and your chosen broker + Initialize Flask, MongoDB, and Celery by adding the following code to your ``app.py`` file: @@ -189,13 +175,18 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your from pymongo import MongoClient 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 = MongoClient(app.config['MONGO_URI']) db = client.get_database(name="newsletter") + # Create a Celery instance celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) celery.conf.update(app.config) @@ -205,13 +196,58 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your if __name__ == '__main__': app.run(debug=True) -This opens a connection to the ``newsletter`` database in your MongoDB cluster -and configures your Celery task queue. +Create a Celery Task +~~~~~~~~~~~~~~~~~~~~ + +The Celery task uses the components instantiated in your ``app.py`` file to send a newsletter email to subscribers. + +The ``@celery.task()`` decorator registers the function as a Celery task. Setting ``bind=True`` means the function receives the task instance as the ``self`` argument, which allows it to access Celery task methods and metadata. For more information about tasks, see the `celery.app.task `__ API documentation. + +Since this task runs outside of Flask's HTTP request cycle, you must manually provide application context by wrapping the email logic in a ``with app.app_context()`` block. This gives Flask access to other components like the Flask-Mail ``mail`` instance and the {+driver-short+} connection to your ``newsletter`` MongoDB database. + +This method loops through the list of ``subscribers``, creates an email using the Flask-Mail ``Message`` class, and then sends it to each user by using the ``mail`` object. After each email is sent, it logs the delivery by inserting a document into your MongoDB ``deliveries`` collection to record that the message was sent. Each email operation is wrapped in a ``try`` block to ensure that in the case of an error, the failure is logged and the database is not updated with a false delivery record. + +Define your ``send_emails()`` method by adding the following code to your ``tasks.py`` file: + +.. code-block:: python + + from flask_mail import Message + from app import app, mail, db, celery + from datetime import datetime + + @celery.task(bind=True) + 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'} + Define Your Routes ~~~~~~~~~~~~~~~~~~ -Define the ``root``, ``admin``, ``subscribe``, and ``send-newsletter`` routes by adding the following code to your ``routes.py`` file: +In Flask, the ``@app.route()`` decorator assigns a URL path to a specific function. In the following code, it is used to define the root (``/``), ``/admin``, ``/subscribe``, and ``/send-newsletter`` routes. The optional ``methods`` parameter is used in some cases to define a list of allowable HTTP methods. + +The ``@app.before_request()`` method sets a function to run before every request. In this case, the function provides some basic security by limiting access to the ``admin`` page to IP addresses listed in the ``ALLOWED_IPS`` parameter defined in the ``config.py`` file. Specifically, access is only allowed for the ``localhost``. + +The root and ``/admin`` routes render pages using the ``render_template()`` method. The ``/subscribe`` and ``/send-newsletter`` routes access request parameters in ``request.form[]`` to execute commands, and then return HTTP responses. + +Define your routes by adding the following code to your ``routes.py`` file: .. code-block:: python @@ -275,14 +311,12 @@ application in this file. Create Your Pages ~~~~~~~~~~~~~~~~~ -You can build your user interface in the ``templates`` directory. +The HTML files in the ``templates`` directory define the user interface, and are written using standard HTML. Since this application uses asynchronous HTTP requests, the scripts in these files use :wikipedia:`Fetch API calls `. These scripts also handle timeouts and errors. -Because this application uses asynchronous messages, the scripts in the -following files use :wikipedia:`Fetch API calls `. They also -handle timeouts and errors. +Subscribe Pages +``````````````` -Copy the following code into your ``subscribe.html`` file to create your -:guilabel:`Subscribe to Newsletter` page. +Copy the following code into your ``subscribe.html`` file to create your :guilabel:`Subscribe to Newsletter` page. .. code-block:: html @@ -340,6 +374,9 @@ Copy the following code into your ``subscribe.html`` file to create your +Admin Page +``````````` + The script for the admin page displays an alert to the user that depends on the success of the ``send_newsletter`` call. @@ -399,8 +436,7 @@ Copy the following code into your ``admin.html`` file to create your Format Your Pages ~~~~~~~~~~~~~~~~~ -You can apply a style sheet to your templates by adding the following code to -the ``styles.css`` file: +You can apply a style sheet to your templates by adding the following code to the ``styles.css`` file: .. code-block:: css @@ -480,14 +516,10 @@ the ``styles.css`` file: color: #666; } -You can modify this style sheet or create your own to customize your -application. - Testing the Platform ~~~~~~~~~~~~~~~~~~~~ -After you complete the previous steps, you have a working application that -uses MongoDB, Flask, and Celery to manage a newsletter platform. +After you complete the previous steps, you have a working application that uses MongoDB, Flask, and Celery to manage a newsletter platform. You can use the following steps to test your application: From a8774306fea7d9e89eb63777c307b9afa330b865 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Wed, 18 Jun 2025 22:49:18 -0400 Subject: [PATCH 10/14] format --- .../integrations/flask-celery-integration.txt | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index c2c2d277..da06e2cb 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -139,22 +139,25 @@ Define the necessary configurations by adding the following code to your ``confi import os class Config: - MAIL_SERVER = 'smtp.gmail.com' - MAIL_PORT = 587 - MAIL_USE_TLS = True MAIL_USERNAME = '' # Your email address without '@gmail.com' MAIL_PASSWORD = '' - ALLOWED_IPS = ['127.0.0.1'] + MAIL_DEFAULT_SENDER = '' MONGO_URI = '' + 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' -You must provide your Gmail credentials (``MAIL_USERNAME`` and ``MAIL_PASSWORD``) to enable your application to send emails. For security purposes, we recommend that you generate an app password to use, rather than using your primary password. For more information, see the `App Password settings `__ in your Google Account. +You must provide your Gmail credentials and email (``MAIL_USERNAME``, ``MAIL_PASSWORD``, and ``MAIL_DEFAULT_SENDER``) to enable your application to send emails. For security purposes, we recommend that you generate an app password to use, rather than using your primary password. For more information, see the `App Password settings `__ in your Google Account. -You must also create a connection string to set into the ``MONGO_URI`` environment variable. For more information see the :ref:`Create a Connection String ` section of this guide. +You must also provide a connection string to set into the ``MONGO_URI`` environment variable. For more information see the :ref:`Create a Connection String ` section of this guide. The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its broker, but you can customize this URL to support other implementations. For more information, see the `Broker Settings `__ section of the Celery documentation. +The ``ALLOWED_IPS`` list is used to control access to the :guilabel:`Send Newsletter` page. The rest of the variables configure the Flask and Celery components. + Initialize Flask, MongoDB, and Celery ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -241,11 +244,11 @@ Define your ``send_emails()`` method by adding the following code to your ``task Define Your Routes ~~~~~~~~~~~~~~~~~~ -In Flask, the ``@app.route()`` decorator assigns a URL path to a specific function. In the following code, it is used to define the root (``/``), ``/admin``, ``/subscribe``, and ``/send-newsletter`` routes. The optional ``methods`` parameter is used in some cases to define a list of allowable HTTP methods. +In Flask, the ``@app.route()`` decorator assigns a URL path to a specific function. In the following code, it is used to define the root (``/``), ``/admin``, ``/subscribe``, and ``/send-newsletters`` routes. The optional ``methods`` parameter is used in some cases to define a list of allowable HTTP methods. The ``@app.before_request()`` method sets a function to run before every request. In this case, the function provides some basic security by limiting access to the ``admin`` page to IP addresses listed in the ``ALLOWED_IPS`` parameter defined in the ``config.py`` file. Specifically, access is only allowed for the ``localhost``. -The root and ``/admin`` routes render pages using the ``render_template()`` method. The ``/subscribe`` and ``/send-newsletter`` routes access request parameters in ``request.form[]`` to execute commands, and then return HTTP responses. +The root and ``/admin`` routes render pages using the ``render_template()`` method. The ``/subscribe`` and ``/send-newsletters`` routes access request parameters in ``request.form[]`` to execute commands, and then return HTTP responses. Define your routes by adding the following code to your ``routes.py`` file: @@ -313,7 +316,7 @@ Create Your Pages The HTML files in the ``templates`` directory define the user interface, and are written using standard HTML. Since this application uses asynchronous HTTP requests, the scripts in these files use :wikipedia:`Fetch API calls `. These scripts also handle timeouts and errors. -Subscribe Pages +Subscribe Page ``````````````` Copy the following code into your ``subscribe.html`` file to create your :guilabel:`Subscribe to Newsletter` page. @@ -516,7 +519,7 @@ You can apply a style sheet to your templates by adding the following code to th color: #666; } -Testing the Platform +Test the Application ~~~~~~~~~~~~~~~~~~~~ After you complete the previous steps, you have a working application that uses MongoDB, Flask, and Celery to manage a newsletter platform. @@ -532,6 +535,24 @@ You can use the following steps to test your application: documentation `__ for your operating system. + On MacOS: + + .. code-block:: bash + + brew services start rabbitmq + + On Windows: + + .. code-block:: bash + + rabbitmq-service start + + On Linux/Unix: + + .. code-block:: bash + + sudo systemctl start rabbitmq-server + .. step:: Start your application Use the following code to start your application: @@ -548,7 +569,7 @@ You can use the following steps to test your application: .. step:: Create a subscriber - Navigate to ``localhost:5000`` in your browser to open the + Navigate to ``__ in your browser to open the :guilabel:`Subscribe to our Newsletter` page. Enter the subscriber information and click :guilabel:`Subscribe`. @@ -559,7 +580,7 @@ You can use the following steps to test your application: .. step:: Dispatch a newsletter - Navigate to ``localhost:5000/admin`` in your browser to open the + Navigate to ``__ in your browser to open the :guilabel:`Send Newsletter` page. Enter the newsletter details and click :guilabel:`Send`. @@ -579,16 +600,12 @@ You can use the following steps to test your application: Next Steps ~~~~~~~~~~ -This application demonstrates how to integrate with the Celery task queue to -manage subscriber data, and send batch emails. You can further enhance this -platform by integrating analytics, customizing email templates, and implementing -automated responses. +This application demonstrates how to integrate a Flask application with the Celery task queue to manage subscriber data, and send batch emails. You can further enhance this platform by integrating analytics, customizing email templates, and implementing automated responses. More Resources -------------- -For more information about the components used in this tutorial, see the following -resources: +For more information about the components used in this tutorial, see the following resources: - `Flask `__ - `Flask Mail `__ From 070b2df6560956af37a6b174b6c6c2ebfc2ad207 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Wed, 18 Jun 2025 23:03:19 -0400 Subject: [PATCH 11/14] format --- .../integrations/flask-celery-integration.txt | 150 +++++++++++++----- 1 file changed, 111 insertions(+), 39 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index da06e2cb..310bcc8d 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -21,29 +21,38 @@ Tutorial: Flask and Celery Integration Overview -------- -In this tutorial, you can learn how to use MongoDB, Flask, and Celery to build a newsletter platform. This application allows users to subscribe to newsletters, and administrators to manage and send batch emails asynchronously. +In this tutorial, you can learn how to use MongoDB, Flask, and Celery to build a +newsletter platform. This application allows users to subscribe to newsletters, +and administrators to manage and send batch emails asynchronously. Flask ~~~~~ Flask is a lightweight web application framework with built-in configuration and convention defaults that provide consistency to developers across projects. For -more information, see the `Flask webpage `__. +more information, see the `Flask webpage +`__. Celery ~~~~~~ -Celery is an open-source distributed task queue that handles large volumes of messages efficiently. It supports asynchronous processing and task scheduling. For more information, see the `Celery webpage `__. +Celery is an open-source distributed task queue that handles large volumes of +messages efficiently. It supports asynchronous processing and task scheduling. +For more information, see the `Celery webpage +`__. Tutorial -------- -This tutorial creates a modified version of the sample application in the :github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project ` GitHub repository. +This tutorial creates a modified version of the sample application in the +:github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project +` GitHub repository. Prerequisites ~~~~~~~~~~~~~ -Ensure that you have the following components installed and set up before you start this tutorial: +Ensure that you have the following components installed and set up before you +start this tutorial: - A MongoDB cluster. We recommend that you use Atlas. To learn how to create an Atlas cluster, see the @@ -52,7 +61,8 @@ Ensure that you have the following components installed and set up before you st - A database named ``newsletter`` in your cluster. For more information, see the :atlas:`Create a Database ` page in the Atlas guide. -- `RabbitMQ `__ to use as a message broker for Celery. +- `RabbitMQ `__ to use as a message + broker for Celery. - `Gmail `__ to use as an SMTP server. For more information about SMTP servers, see the :wikipedia:`Simple Mail Transfer Protocol ` Wikipedia page. @@ -65,8 +75,10 @@ Setup :style: connected .. step:: Create your project directory and structure - - The name of your project directory is ``newsletter``. Create your directory and navigate to it by running the following commands in terminal: + + The name of your project directory is ``newsletter``. Create your + directory and navigate to it by running the following commands in + terminal: .. code-block:: bash @@ -80,7 +92,8 @@ Setup MongoDB connection details, mail server configuration, Celery broker connection, and any other environment-specific variables - ``tasks.py``: Defines background tasks to send emails asynchronously - - ``routes.py``: Defines the routes (URLs) that your application responds to + - ``routes.py``: Defines the routes (URLs) that your application responds + to We recommend structuring your application to separate concerns, which can make the application modular and more maintainable. @@ -104,8 +117,10 @@ Setup Your application depends on the following libraries: - - `Flask `__ for handling the web server and routing - - `Flask Mail `__ for sending emails from your application + - `Flask `__ for handling + the web server and routing + - `Flask Mail `__ for sending emails + from your application - :ref:`{+driver-short+} ` - `Celery `__ to manage tasks, such as sending batch emails @@ -117,7 +132,8 @@ Setup different versions of libraries for different projects. Before running any ``pip`` commands, ensure that your ``virtualenv`` is active. - Run the following ``pip`` command in your terminal to install the dependencies: + Run the following ``pip`` command in your terminal to install the + dependencies: .. code-block:: bash @@ -126,13 +142,15 @@ Setup Configure Your Application ~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``config.py`` file contains the settings and credentials to perform the following actions: +The ``config.py`` file contains the settings and credentials to perform the +following actions: - Connect Celery to RabbitMQ as its message broker - Configure Flask-Mail to use Gmail as its SMTP server - Connect your application to your MongoDB server -Define the necessary configurations by adding the following code to your ``config.py`` file: +Define the necessary configurations by adding the following code to your +``config.py`` file: .. code-block:: python @@ -150,22 +168,37 @@ Define the necessary configurations by adding the following code to your ``confi CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' RESULT_BACKEND = MONGO_URI + '/celery_results' -You must provide your Gmail credentials and email (``MAIL_USERNAME``, ``MAIL_PASSWORD``, and ``MAIL_DEFAULT_SENDER``) to enable your application to send emails. For security purposes, we recommend that you generate an app password to use, rather than using your primary password. For more information, see the `App Password settings `__ in your Google Account. +You must provide your Gmail credentials and email (``MAIL_USERNAME``, +``MAIL_PASSWORD``, and ``MAIL_DEFAULT_SENDER``) to enable your application to +send emails. For security purposes, we recommend that you generate an app +password to use, rather than using your primary password. For more information, +see the `App Password settings `__ in +your Google Account. -You must also provide a connection string to set into the ``MONGO_URI`` environment variable. For more information see the :ref:`Create a Connection String ` section of this guide. +You must also provide a connection string to set into the ``MONGO_URI`` +environment variable. For more information see the :ref:`Create a Connection +String ` section of this guide. -The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its broker, but you can customize this URL to support other implementations. For more information, see the `Broker Settings `__ section of the Celery documentation. +The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its +broker, but you can customize this URL to support other implementations. For +more information, see the `Broker Settings +`__ +section of the Celery documentation. -The ``ALLOWED_IPS`` list is used to control access to the :guilabel:`Send Newsletter` page. The rest of the variables configure the Flask and Celery components. +The ``ALLOWED_IPS`` list is used to control access to the :guilabel:`Send +Newsletter` page. The rest of the variables configure the Flask and Celery +components. Initialize Flask, MongoDB, and Celery ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``app.py`` file initializes and configures the core components of the Flask application. It performs the following tasks: +The ``app.py`` file initializes and configures the core components of the Flask +application. It performs the following tasks: - Creates a Flask application and loads configuration constants - Initializes a Flask-Mail instance with the app's mail server settings -- Connects to the ``newsletter`` MongoDB database by using the {+driver-short+} driver +- Connects to the ``newsletter`` MongoDB database by using the {+driver-short+} + driver - Creates a Celery instance configured with the Flask app and your chosen broker Initialize Flask, MongoDB, and Celery by adding the following code to your @@ -202,15 +235,32 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your Create a Celery Task ~~~~~~~~~~~~~~~~~~~~ -The Celery task uses the components instantiated in your ``app.py`` file to send a newsletter email to subscribers. - -The ``@celery.task()`` decorator registers the function as a Celery task. Setting ``bind=True`` means the function receives the task instance as the ``self`` argument, which allows it to access Celery task methods and metadata. For more information about tasks, see the `celery.app.task `__ API documentation. - -Since this task runs outside of Flask's HTTP request cycle, you must manually provide application context by wrapping the email logic in a ``with app.app_context()`` block. This gives Flask access to other components like the Flask-Mail ``mail`` instance and the {+driver-short+} connection to your ``newsletter`` MongoDB database. - -This method loops through the list of ``subscribers``, creates an email using the Flask-Mail ``Message`` class, and then sends it to each user by using the ``mail`` object. After each email is sent, it logs the delivery by inserting a document into your MongoDB ``deliveries`` collection to record that the message was sent. Each email operation is wrapped in a ``try`` block to ensure that in the case of an error, the failure is logged and the database is not updated with a false delivery record. - -Define your ``send_emails()`` method by adding the following code to your ``tasks.py`` file: +The Celery task uses the components instantiated in your ``app.py`` file to send +a newsletter email to subscribers. + +The ``@celery.task()`` decorator registers the function as a Celery task. +Setting ``bind=True`` means the function receives the task instance as the +``self`` argument, which allows it to access Celery task methods and metadata. +For more information about tasks, see the `celery.app.task +`__ API +documentation. + +Since this task runs outside of Flask's HTTP request cycle, you must manually +provide application context by wrapping the email logic in a ``with +app.app_context()`` block. This gives Flask access to other components like the +Flask-Mail ``mail`` instance and the {+driver-short+} connection to your +``newsletter`` MongoDB database. + +This method loops through the list of ``subscribers``, creates an email using +the Flask-Mail ``Message`` class, and then sends it to each user by using the +``mail`` object. After each email is sent, it logs the delivery by inserting a +document into your MongoDB ``deliveries`` collection to record that the message +was sent. Each email operation is wrapped in a ``try`` block to ensure that in +the case of an error, the failure is logged and the database is not updated with +a false delivery record. + +Define your ``send_emails()`` method by adding the following code to your +``tasks.py`` file: .. code-block:: python @@ -236,7 +286,7 @@ Define your ``send_emails()`` method by adding the following code to your ``task print("Email sent") except Exception as e: - print(f"Failed to send email to {subscriber['email']}: {str(e)}") + print(f"Failed to send email to {subscriber['email']}: {str(e)}") return {'result': 'All emails sent'} @@ -244,11 +294,22 @@ Define your ``send_emails()`` method by adding the following code to your ``task Define Your Routes ~~~~~~~~~~~~~~~~~~ -In Flask, the ``@app.route()`` decorator assigns a URL path to a specific function. In the following code, it is used to define the root (``/``), ``/admin``, ``/subscribe``, and ``/send-newsletters`` routes. The optional ``methods`` parameter is used in some cases to define a list of allowable HTTP methods. +In Flask, the ``@app.route()`` decorator assigns a URL path to a specific +function. In the following code, it is used to define the root (``/``), +``/admin``, ``/subscribe``, and ``/send-newsletters`` routes. The optional +``methods`` parameter is used in some cases to define a list of allowable HTTP +methods. -The ``@app.before_request()`` method sets a function to run before every request. In this case, the function provides some basic security by limiting access to the ``admin`` page to IP addresses listed in the ``ALLOWED_IPS`` parameter defined in the ``config.py`` file. Specifically, access is only allowed for the ``localhost``. +The ``@app.before_request()`` method sets a function to run before every +request. In this case, the function provides some basic security by limiting +access to the ``admin`` page to IP addresses listed in the ``ALLOWED_IPS`` +parameter defined in the ``config.py`` file. Specifically, access is only +allowed for the ``localhost``. -The root and ``/admin`` routes render pages using the ``render_template()`` method. The ``/subscribe`` and ``/send-newsletters`` routes access request parameters in ``request.form[]`` to execute commands, and then return HTTP responses. +The root and ``/admin`` routes render pages using the ``render_template()`` +method. The ``/subscribe`` and ``/send-newsletters`` routes access request +parameters in ``request.form[]`` to execute commands, and then return HTTP +responses. Define your routes by adding the following code to your ``routes.py`` file: @@ -314,12 +375,17 @@ application in this file. Create Your Pages ~~~~~~~~~~~~~~~~~ -The HTML files in the ``templates`` directory define the user interface, and are written using standard HTML. Since this application uses asynchronous HTTP requests, the scripts in these files use :wikipedia:`Fetch API calls `. These scripts also handle timeouts and errors. +The HTML files in the ``templates`` directory define the user interface, and are +written using standard HTML. Since this application uses asynchronous HTTP +requests, the scripts in these files use :wikipedia:`Fetch API calls +`. These scripts also handle timeouts and +errors. Subscribe Page ``````````````` -Copy the following code into your ``subscribe.html`` file to create your :guilabel:`Subscribe to Newsletter` page. +Copy the following code into your ``subscribe.html`` file to create your +:guilabel:`Subscribe to Newsletter` page. .. code-block:: html @@ -439,7 +505,8 @@ Copy the following code into your ``admin.html`` file to create your Format Your Pages ~~~~~~~~~~~~~~~~~ -You can apply a style sheet to your templates by adding the following code to the ``styles.css`` file: +You can apply a style sheet to your templates by adding the following code to +the ``styles.css`` file: .. code-block:: css @@ -522,7 +589,8 @@ You can apply a style sheet to your templates by adding the following code to th Test the Application ~~~~~~~~~~~~~~~~~~~~ -After you complete the previous steps, you have a working application that uses MongoDB, Flask, and Celery to manage a newsletter platform. +After you complete the previous steps, you have a working application that uses +MongoDB, Flask, and Celery to manage a newsletter platform. You can use the following steps to test your application: @@ -600,7 +668,10 @@ You can use the following steps to test your application: Next Steps ~~~~~~~~~~ -This application demonstrates how to integrate a Flask application with the Celery task queue to manage subscriber data, and send batch emails. You can further enhance this platform by integrating analytics, customizing email templates, and implementing automated responses. +This application demonstrates how to integrate a Flask application with the +Celery task queue to manage subscriber data, and send batch emails. You can +further enhance this platform by integrating analytics, customizing email +templates, and implementing automated responses. More Resources -------------- @@ -612,4 +683,5 @@ For more information about the components used in this tutorial, see the followi - `Celery `__ - `RabbitMQ `__ -To find support or to contribute to the MongoDB community, see the `MongoDB Developer Community `__ page. \ No newline at end of file +To find support or to contribute to the MongoDB community, see the `MongoDB +Developer Community `__ page. \ No newline at end of file From f0c6ab8b0975031f8e625232b2d6b6076272dd7a Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Thu, 19 Jun 2025 00:11:20 -0400 Subject: [PATCH 12/14] typos --- .../integrations/flask-celery-integration.txt | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index 310bcc8d..6a7f83f1 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -89,7 +89,7 @@ Setup - ``app.py``: The main entry point for your Flask application - ``config.py``: Configuration settings for your application, including - MongoDB connection details, mail server configuration, Celery broker + the MongoDB connection URI, mail server configuration, Celery broker connection, and any other environment-specific variables - ``tasks.py``: Defines background tasks to send emails asynchronously - ``routes.py``: Defines the routes (URLs) that your application responds @@ -115,11 +115,11 @@ Setup .. step:: Install the required Python packages - Your application depends on the following libraries: + Your application uses the following libraries: - `Flask `__ for handling the web server and routing - - `Flask Mail `__ for sending emails + - `Flask-Mail `__ for sending emails from your application - :ref:`{+driver-short+} ` - `Celery `__ to manage tasks, such @@ -142,12 +142,12 @@ Setup Configure Your Application ~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``config.py`` file contains the settings and credentials to perform the +The ``config.py`` file contains settings and credentials to perform the following actions: - Connect Celery to RabbitMQ as its message broker - Configure Flask-Mail to use Gmail as its SMTP server -- Connect your application to your MongoDB server +- Connect your application to your MongoDB deployment Define the necessary configurations by adding the following code to your ``config.py`` file: @@ -175,8 +175,8 @@ password to use, rather than using your primary password. For more information, see the `App Password settings `__ in your Google Account. -You must also provide a connection string to set into the ``MONGO_URI`` -environment variable. For more information see the :ref:`Create a Connection +You must also provide a connection string to set as the ``MONGO_URI`` +environment variable. For more information, see the :ref:`Create a Connection String ` section of this guide. The provided Celery broker URL (``CELERY_BROKER_URL``) specifies RabbitMQ as its @@ -192,7 +192,7 @@ components. Initialize Flask, MongoDB, and Celery ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``app.py`` file initializes and configures the core components of the Flask +The ``app.py`` file initializes and configures the core components of your application. It performs the following tasks: - Creates a Flask application and loads configuration constants @@ -251,15 +251,15 @@ app.app_context()`` block. This gives Flask access to other components like the Flask-Mail ``mail`` instance and the {+driver-short+} connection to your ``newsletter`` MongoDB database. -This method loops through the list of ``subscribers``, creates an email using +This function loops through the list of ``subscribers``, creates an email using the Flask-Mail ``Message`` class, and then sends it to each user by using the ``mail`` object. After each email is sent, it logs the delivery by inserting a document into your MongoDB ``deliveries`` collection to record that the message -was sent. Each email operation is wrapped in a ``try`` block to ensure that in +was sent. Each email operation is wrapped in a ``try`` block to ensure that, in the case of an error, the failure is logged and the database is not updated with a false delivery record. -Define your ``send_emails()`` method by adding the following code to your +Define your ``send_emails()`` function by adding the following code to your ``tasks.py`` file: .. code-block:: python @@ -297,10 +297,10 @@ Define Your Routes In Flask, the ``@app.route()`` decorator assigns a URL path to a specific function. In the following code, it is used to define the root (``/``), ``/admin``, ``/subscribe``, and ``/send-newsletters`` routes. The optional -``methods`` parameter is used in some cases to define a list of allowable HTTP -methods. +``methods`` parameter is used in some instances to define a list of allowable +HTTP methods. -The ``@app.before_request()`` method sets a function to run before every +The ``@app.before_request()`` decorator sets a function to run before every request. In this case, the function provides some basic security by limiting access to the ``admin`` page to IP addresses listed in the ``ALLOWED_IPS`` parameter defined in the ``config.py`` file. Specifically, access is only @@ -372,14 +372,14 @@ Define your routes by adding the following code to your ``routes.py`` file: You can add more security protections or customize user-facing alerts for your application in this file. -Create Your Pages -~~~~~~~~~~~~~~~~~ +Create Your Page Templates +~~~~~~~~~~~~~~~~~~~~~~~~~~ The HTML files in the ``templates`` directory define the user interface, and are -written using standard HTML. Since this application uses asynchronous HTTP -requests, the scripts in these files use :wikipedia:`Fetch API calls -`. These scripts also handle timeouts and -errors. +written using standard HTML. Because this application uses asynchronous HTTP +requests, the scripts in these files use `Fetch API calls +`__. These scripts +also handle timeouts and errors. Subscribe Page ``````````````` @@ -446,7 +446,7 @@ Copy the following code into your ``subscribe.html`` file to create your Admin Page ``````````` -The script for the admin page displays an alert to the user that depends on the +The admin page script displays an alert to the user that indicates the success of the ``send_newsletter`` call. Copy the following code into your ``admin.html`` file to create your @@ -644,7 +644,7 @@ You can use the following steps to test your application: To confirm that you created a new subscriber, open `Atlas `__ and navigate to the - ``users`` collection in your ``newletter`` database. + ``users`` collection in your ``newsletter`` database. .. step:: Dispatch a newsletter @@ -669,17 +669,23 @@ Next Steps ~~~~~~~~~~ This application demonstrates how to integrate a Flask application with the -Celery task queue to manage subscriber data, and send batch emails. You can -further enhance this platform by integrating analytics, customizing email -templates, and implementing automated responses. +Celery task queue to manage subscriber data and send batch emails. You can +build on this application to experiment with Flask or Celery. Some possible +improvements include the following changes: + +- Add `retries `__ to your ``send_emails`` function +- `Format your newsletter `__ +- Implement more rigorous `security features `__ More Resources -------------- -For more information about the components used in this tutorial, see the following resources: +For more information about the components used in this tutorial, see the +following resources: - `Flask `__ -- `Flask Mail `__ +- `Flask-Mail `__ - `Celery `__ - `RabbitMQ `__ From 059faec6a0d4e56369a4d13a0f40efef81794433 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Thu, 19 Jun 2025 16:18:55 -0400 Subject: [PATCH 13/14] use flask_pymongo.PyMongo --- source/integrations/flask-celery-integration.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index 6a7f83f1..2152e861 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -161,6 +161,7 @@ Define the necessary configurations by adding the following code to your MAIL_PASSWORD = '' MAIL_DEFAULT_SENDER = '' MONGO_URI = '' + DATABASE_NAME = "newsletter" ALLOWED_IPS = ['127.0.0.1'] MAIL_SERVER = 'smtp.gmail.com' MAIL_PORT = 587 @@ -208,7 +209,7 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your from flask import Flask from flask_mail import Mail - from pymongo import MongoClient + from flask_pymongo import PyMongo from celery import Celery # Create a Flask application @@ -219,8 +220,8 @@ Initialize Flask, MongoDB, and Celery by adding the following code to your mail = Mail(app) # Connect to MongoDB - client = MongoClient(app.config['MONGO_URI']) - db = client.get_database(name="newsletter") + client = PyMongo(app).cx + db = client[app.config['DATABASE_NAME']] # Create a Celery instance celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) From 533958b6e5afec4ab2bc0360fce092f2ce4d23e6 Mon Sep 17 00:00:00 2001 From: Rachel Mackintosh Date: Fri, 20 Jun 2025 20:05:44 -0400 Subject: [PATCH 14/14] update github link --- source/integrations/flask-celery-integration.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/integrations/flask-celery-integration.txt b/source/integrations/flask-celery-integration.txt index 2152e861..c25a3826 100644 --- a/source/integrations/flask-celery-integration.txt +++ b/source/integrations/flask-celery-integration.txt @@ -44,9 +44,9 @@ For more information, see the `Celery webpage Tutorial -------- -This tutorial creates a modified version of the sample application in the -:github:`Newsletter Platform with JavaScript, Flask, and MongoDB sample project -` GitHub repository. +This tutorial recreates the sample application in the :github:`Newsletter +Platform with JavaScript, Flask, and MongoDB sample project +` GitHub repository. Prerequisites ~~~~~~~~~~~~~