Construa uma plataforma de boletim de notícias com Flask e MongoDB
Mercy Bassey11 min read • Published Jun 27, 2024 • Updated Sep 04, 2024
APLICATIVO COMPLETO
Avalie esse Tutorial
Uma newsletter é uma ferramenta poderosa para manter uma comunicação regular com seu público. Ele conecta você com seus assinantes, permitindo que você compartilhe atualizações, notícias e outros conteúdos valiosos diretamente em suas caixas de entrada. Neste artigo, você aprenderá como criar uma plataforma de newsletter dinâmica e interativa onde os assinantes podem assinar facilmente sua newsletter e você, como administrador, pode gerenciar e enviar e-mails em lote com eficiência para todos os usuários inscritos. Ao final deste guia, você terá uma plataforma de boletim informativo totalmente funcional que utiliza o JavaScript para interatividade, o Flask no lado do servidor e o MongoDB para armazenamento eficiente de dados.
Para acompanhar este artigo, você deve atender aos seguintes requisitos:
- Mongosh para interagir com sua instância do MongoDB — veja as instruções de instalação
- RabbitMQ instalado em sua máquina para intermediação de mensagens — veja as instruções de instalação para Debian e Ubuntu, depois Windows e macOS usando Homebrew
- Gmail como servidor SMTP para enviar e-mails — nesse caso, gere uma senha de aplicativo para autenticar seu aplicativo com segurança sem usar a senha primária da sua conta do Gmail
Os comandos usados neste tutorial são demonstrados em uma máquina Linux com um Ubuntu 22.04Distribuição LTS. O código usado neste tutorial pode ser encontrado no repositório GitHub.
Para começar, você deve garantir que o MongoDB, Mongosh e seu servidor RubyMQ estejam em execução. Para atingir isso, execute os seguintes comandos sequencialmente:
1 sudo systemctl status mongod 2 sudo systemctl status rabbitmq-server 3 mongosh
Se você tiver a seguinte saída, você está configurado:
1 ● mongod.service - MongoDB Database Server 2 Loaded: loaded (/lib/systemd/system/mongod.service; enabled; vendor preset: enabled) 3 Active: active (running) since Tue 2024-06-04 16:47:23 WAT; 13h ago 4 Docs: https://docs.mongodb.org/manual 5 Main PID: 1305 (mongod) 6 Memory: 259.0M 7 CPU: 2min 8.508s 8 CGroup: /system.slice/mongod.service 9 └─1305 /usr/bin/mongod --config /etc/mongod.conf 10 11 Jun 04 16:47:23 mercy systemd[1]: Started MongoDB Database Server. 12 Jun 04 16:47:24 mercy mongod[1305]: {"t":{"$date":"2024-06-04T15:47:24.620Z"},"s":"I", "c":"CONTROL", "id":7484500, "ctx":"main","msg":"Environment variabl> 13 14 ● rabbitmq-server.service - RabbitMQ Messaging Server 15 Loaded: loaded (/lib/systemd/system/rabbitmq-server.service; enabled; vendor preset: enabled) 16 Active: active (running) since Tue 2024-06-04 16:47:28 WAT; 13h ago 17 Main PID: 781 (beam.smp) 18 Tasks: 27 (limit: 9003) 19 Memory: 125.1M 20 CPU: 1min 55.438s 21 CGroup: /system.slice/rabbitmq-server.service 22 ├─ 781 /usr/lib/erlang/erts-12.2.1/bin/beam.smp -W w -MBas ageffcbf -MHas ageffcbf -MBlmbcs 512 -MHlmbcs 512 -MMmcs 30 -P 1048576 -t 5000000 -st> 23 ├─ 866 erl_child_setup 65536 24 ├─1204 inet_gethost 4 25 └─1205 inet_gethost 4 26 27 Jun 04 16:47:19 mercy systemd[1]: Starting RabbitMQ Messaging Server... 28 Jun 04 16:47:28 mercy systemd[1]: Started RabbitMQ Messaging Server. 29 30 Current Mongosh Log ID: 665ff402cc42191d77a26a12 31 Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.2.6 32 Using MongoDB: 7.0.11 33 Using Mongosh: 2.2.6 34 35 For mongosh info see: https://docs.mongodb.com/mongodb-shell/ 36 37 ------ 38 The server generated these startup warnings when booting 39 2024-06-04T16:47:24.825+01:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem 40 2024-06-04T16:47:26.247+01:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted 41 2024-06-04T16:47:26.247+01:00: vm.max_map_count is too low 42 ------ 43 44 test>
Em seguida, crie um diretório de trabalho e um ambiente virtual e, depois, ative o ambiente virtual usando os seguintes comandos:
1 mkdir newsletter 2 cd newsletter 3 code . 4 python3 -m venv .venv 5 . .venv/bin/activate # For Mac/Linux OS 6 .venv\Scripts\activate # For Windows OS
Com o ambiente virtual ativado, agora você está pronto para instalar as bibliotecas necessárias para desenvolver sua plataforma de boletins informativos. Para continuar, você precisará instalar as seguintes bibliotecas:
- Flask para lidar com o servidor web e roteamento
- Flask Mail para enviar e-mails a partir do seu aplicativo
- PyMongo para interface com o MongoDB, que você pode usar para gerenciar dados de assinantes e armazenamento persistente de conteúdo de boletins informativos
- Celery para gerenciar tarefas assíncronas, como envio de e-mails em lote
Usando o seguinte comando, você os instalará em seu ambiente virtual:
1 pip install Flask Flask-Mail pymongo celery
Finalmente, em seu diretório de trabalho, crie dois diretórios chamados
static
e templates
. Eles servirão como locais para arquivos estáticos, como modelos CSS e HTML, essenciais para renderizar a parte frontend do seu aplicativo da web. Após isso, crie os seguintes arquivos:app.py
: Isso servirá como o principal ponto de entrada para seu aplicativo Flask, onde você inicializa seu aplicativo e une os outros componentes.config.py
: Esse arquivo conterá todas as configurações do seu aplicativo, como detalhes da conexão do MongoDB, configuração do servidor de e-mail e conexão do Celery Broker, além de outras variáveis específicas do ambiente.routes.py
: Aqui você definirá as rotas (URL) que sua aplicação responderá. Ele incluirá funções para lidar com solicitações e respostas, conectando URLs a funções Python.tasks.py
: Esse arquivo será usado para definir tarefas em segundo plano que podem ser processadas de forma assíncrona, ou seja, neste caso, para enviar e-mails.
Com seu ambiente configurado, a próxima coisa a fazer é desenvolver a aparência da plataforma de boletim informativo. No diretório de modelos, crie dois arquivos HTML -
admin.html
e subscrbe.html
. Emadmin.html
, adicione a seguinte marcação HTML:1 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Admin - Send Newsletter</title> 7 <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> 8 </head> 9 <body> 10 <h1>Send Newsletter</h1> 11 <form id="admin-form"> 12 <label for="title">Title:</label> 13 <input type="text" id="title" name="title" required> 14 <br> 15 <label for="body">Body:</label> 16 <textarea id="body" name="body" required></textarea> 17 <br> 18 <button type="submit">Send</button> 19 </form> 20 <div id="response"></div> 21 </body> 22 </html>
E então adicione o seguinte código no
subscribe.html
arquivo :1 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Subscribe to Newsletter</title> 7 <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}"> 8 </head> 9 <body> 10 <h1>Subscribe to our Newsletter</h1> 11 <form id="subscribe-form"> 12 <label for="firstname">First Name:</label> 13 <input type="text" id="firstname" name="firstname" required> 14 <br> 15 <label for="lastname">Last Name:</label> 16 <input type="text" id="lastname" name="lastname" required> 17 <br> 18 <label for="email">Email:</label> 19 <input type="email" id="email" name="email" required> 20 <br> 21 <button type="submit">Subscribe</button> 22 </form> 23 <div id="response"></div> 24 25 <footer> 26 Made with ❤️ © 2024 Mercy 27 </footer> 28 </body> 29 </html>
Nos modelos
admin.html
e subscribe.html
, adicione os seguintes scripts, respectivamente, na tag body:1 <script> 2 document.getElementById('admin-form').addEventListener('submit', function(event) { 3 event.preventDefault(); 4 var formData = new FormData(event.target); 5 fetch('/send-newsletters', { 6 method: 'POST', 7 body: formData 8 }) 9 .then(response => response.json()) 10 .then(() => { 11 document.getElementById('response').innerText = 'Emails are being sent!'; 12 setTimeout(() => { 13 document.getElementById('response').innerText = ''; 14 }, 3000); 15 document.getElementById('admin-form').reset(); 16 }) 17 .catch(error => { 18 document.getElementById('response').innerText = 'Error sending emails.'; 19 setTimeout(() => { 20 document.getElementById('response').innerText = ''; 21 }, 3000); 22 console.error('Error:', error); 23 }); 24 }); 25 </script>
1 <script> 2 document.getElementById('subscribe-form').addEventListener('submit', function(event) { 3 event.preventDefault(); 4 var formData = new FormData(event.target); 5 fetch('/subscribe', { 6 method: 'POST', 7 body: formData 8 }).then(response => { 9 if (!response.ok) { 10 throw response; 11 } 12 return response.text(); 13 }).then(data => { 14 document.getElementById('response').innerHTML = data; 15 document.getElementById('subscribe-form').reset(); 16 setTimeout(() => { 17 document.getElementById('response').innerHTML = ''; 18 }, 3000); 19 }).catch(error => { 20 error.text().then(errorMessage => { 21 document.getElementById('response').innerHTML = errorMessage; 22 setTimeout(() => { 23 document.getElementById('response').innerHTML = ''; 24 }, 3000); 25 }); 26 }); 27 }); 28 </script>
Para o modelo
admin.html
, o bloco de script garante que o envio do formulário para o envio de boletins informativos seja tratado de forma assíncrona. Quando o formulário de administração é enviado, o JavaScript intercepta esse evento para evitar o recarregamento da página. Em seguida, ele envia os dados do formulário para o servidor usando a API Fetch. Em caso de sucesso, ele exibe uma mensagem informando que os e-mails estão sendo enviados, e essa mensagem é apagada após alguns segundos. Em caso de erro durante o envio do formulário, ele captura o erro e exibe uma mensagem apropriada para o administrador.Para o modelo
subscribe.html
, o bloco de script garante que o processo de assinatura seja tratado de forma semelhante e assíncrona. Quando um usuário envia os detalhes da assinatura, o script impede o envio do formulário padrão para o servidor e, em vez disso, envia os dados usando Fetch. A resposta do servidor é então exibida diretamente no HTML. Se a resposta indicar sucesso, será exibida uma mensagem de confirmação e, se houver um erro (como o fato de o servidor responder que o e-mail já existe no banco de dados), será exibida a mensagem de erro.Por fim, crie um arquivo
styles.css
em sua pasta estática e adicione os seguintes estilos:1 @import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap'); 2 3 body { 4 font-family: "Nunito", sans-serif; 5 font-optical-sizing: auto; 6 font-weight: 300; 7 font-style: normal; 8 margin: 0; 9 padding: 0; 10 display: flex; 11 flex-direction: column; 12 align-items: center; 13 justify-content: center; 14 height: 100vh; 15 background-color: #040100; 16 } 17 18 h1 { 19 color: white; 20 } 21 22 form { 23 background: #DB4918; 24 padding: 30px 40px; 25 border-radius: 8px; 26 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); 27 width: 100%; 28 max-width: 400px; 29 margin: 20px 0; 30 } 31 32 label { 33 display: block; 34 margin-bottom: 8px; 35 font-weight: bold; 36 color: white; 37 } 38 39 input[type="text"], 40 input[type="email"], 41 textarea { 42 width: 100%; 43 padding: 10px; 44 margin-bottom: 10px; 45 border: 1px solid #ccc; 46 border-radius: 4px; 47 font-size: 16px; 48 } 49 50 button { 51 background: #DB8218; 52 color: white; 53 padding: 10px 20px; 54 border: none; 55 border-radius: 4px; 56 cursor: pointer; 57 font-size: 16px; 58 font-family: "Nunito", sans-serif; 59 } 60 61 button:hover { 62 background: #DB6B18; 63 } 64 65 #response { 66 margin-top: 20px; 67 font-size: 16px; 68 color: #28a745; 69 } 70 71 footer { 72 text-align: center; 73 padding: 20px; 74 margin-top: 20px; 75 font-size: 16px; 76 color: #666; 77 }
Com o modelo configurado, agora você está pronto para definir as rotas específicas e as tarefas em segundo plano que impulsionarão a funcionalidade de sua plataforma de newsletter. Isso envolve o mapeamento de URLs para funções Python no seu aplicativo Flask, que tratará de envios de formulários, interações de usuários e quaisquer outros processos necessários. Além disso, você configurará tarefas do Celery para lidar com operações assíncronas, como o envio de e-mails em lotes.
Para começar, adicione o seguinte em seu
config.py
:1 import os 2 3 class Config: 4 CELERY_BROKER_URL = 'amqp://guest:guest@localhost//' 5 RESULT_BACKEND = 'mongodb://localhost:27017/celery_results' 6 MAIL_SERVER = 'smtp.gmail.com' 7 MAIL_PORT = 587 8 MAIL_USE_TLS = True 9 MAIL_USERNAME = '<username>' # Your email address without the '@gmail.com' 10 MAIL_PASSWORD = '<app password>' 11 MAIL_DEFAULT_SENDER = '<email address>' 12 ALLOWED_IPS = ['127.0.0.1'] 13 MONGO_URI = 'mongodb://localhost:27017/newsletter'
Aqui você está definindo a configuração para seu aplicativo Flask. Essa configuração inclui as configurações para que o Celery se conecte ao seu agente de mensagens (RabbitMQ neste caso, indicado pela URL do AMQP) e MongoDB para o back-end de resultados. Você também está configurando o Flask-Mail com o Gmail como o servidor SMTP para lidar com e-mails enviados, o que requer os detalhes do servidor de e-mail, a porta e as preferências de conexão segura, juntamente com suas credenciais do Gmail. O
MAIL_DEFAULT_SENDER
é usado como o endereço de e-mail do remetente padrão para seus e-mails enviados. Além disso, ALLOWED_IPS
é especificado para uma camada extra de segurança, limitando o acesso a determinadas funcionalidades com base no IP do solicitante. Por fim, o MONGO_URI
define a string de conexão para o MongoDB database, onde as informações do assinante e outros dados relevantes para o sistema de newsletter serão armazenados.Em seguida, no seu
routes.py
arquivo, adicione os seguintes trechos de código:1 from flask import render_template, request, abort, jsonify 2 from app import app, db 3 from tasks import send_emails 4 5 6 def limit_remote_addr(): 7 if 'X-Forwarded-For' in request.headers: 8 remote_addr = request.headers['X-Forwarded-For'].split(',')[0] 9 else: 10 remote_addr = request.remote_addr 11 12 if request.endpoint == 'admin' and remote_addr not in app.config['ALLOWED_IPS']: 13 abort(403) 14 15 16 def home(): 17 return render_template('subscribe.html') 18 19 20 def admin(): 21 return render_template('admin.html') 22 23 24 def subscribe(): 25 first_name = request.form['firstname'] 26 last_name = request.form['lastname'] 27 email = request.form['email'] 28 29 if db.users.find_one({'email': email}): 30 return """ 31 <div class="response error"> 32 <span class="icon">✖</span> This email is already subscribed! 33 </div> 34 """, 409 35 36 db.users.insert_one({'firstname': first_name, 'lastname': last_name, 'email': email, 'subscribed': True}) 37 return """ 38 <div class="response success"> 39 <span class="icon">✔</span> Subscribed successfully! 40 </div> 41 """, 200 42 43 44 def send_newsletters(): 45 title = request.form['title'] 46 body = request.form['body'] 47 subscribers = list(db.users.find({'subscribed': True})) 48 49 for subscriber in subscribers: 50 subscriber['_id'] = str(subscriber['_id']) 51 52 send_emails.apply_async(args=[subscribers, title, body]) 53 return jsonify({'message': 'Emails are being sent!'}), 202
O trecho de código acima estabelece as rotas e as funcionalidades essenciais para sua plataforma de boletim informativo. A função
limit_remote_addr
restringe o acesso à interface de administração com base no IP para aumentar a segurança. O endpoint /subscribe
lida com as assinaturas dos usuários verificando se há entradas duplicadas antes de salvar os dados dos novos assinantes no MongoDB. A rota/send-newsletters
aciona o envio assíncrono de e-mails para os assinantes usando o Celery, permitindo operações sem bloqueio e feedback imediato para o usuário de que os e-mails estão sendo enviados.No seu
tasks.py
, adicione os seguintes trechos de código:1 from flask_mail import Message 2 from app import app, mail, db, celery 3 from datetime import datetime 4 5 6 def send_emails(self, subscribers, title, body): 7 with app.app_context(): 8 for subscriber in subscribers: 9 try: 10 print(f"Sending email to {subscriber['email']}") 11 msg = Message(title, recipients=[subscriber['email']]) 12 msg.body = body 13 mail.send(msg) 14 db.deliveries.insert_one({ 15 'email': subscriber['email'], 16 'title': title, 17 'body': body, 18 'delivered_at': datetime.utcnow() 19 }) 20 print("Email sent") 21 22 except Exception as e: 23 print(f"Failed to send email to {subscriber['email']}: {str(e)}") 24 25 return {'result': 'All emails sent'}
Isso configurará uma tarefa do Celery que trata do envio de e-mails de forma assíncrona. Quando a
send_emails
tarefa é chamada, ela percorre cada assinante, compondo e enviando um e-mail usando Flask-Mail. Para cada e-mail enviado com sucesso, os detalhes são registrados na collection do MongoDB deliveries
com o e-mail do destinatário, o título do e-mail, o corpo e o carimbo de data/hora de quando foi enviado. Se ocorrer um erro durante o processo de envio de e-mail, ele será capturado e registrado, o que garante que o Celery lide com as falhas e mantenha um registro de todas as tentativas de transmissão de e-mail.Por fim, em seu
app.py
, adicione os seguintes trechos de código:1 from flask import Flask 2 from flask_mail import Mail 3 from pymongo import MongoClient 4 from celery import Celery 5 6 app = Flask(__name__) 7 app.config.from_object('config.Config') 8 9 mail = Mail(app) 10 client = MongoClient(app.config['MONGO_URI']) 11 db = client.get_database() 12 13 celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) 14 celery.conf.update(app.config) 15 16 from routes import * 17 from tasks import * 18 19 if __name__ == '__main__': 20 app.run(debug=True)
Isso inicializará seu aplicativo Flask usando configurações carregadas do seu arquivo de configuração. Ele configura o Flusk-Mail para a funcionalidade de e-mail, conecta-se ao MongoDB usando o PyMongo e configura o Celory com o operador especificado no arquivo de configuração. Em seguida, as rotas e tarefas são importadas para integrar definições de endpoints e funções de tarefas em segundo plano no aplicativo. Além disso, ele executa o aplicativo no modo de depuração para permitir a depuração e o desenvolvimento em tempo real, facilitando o rastreamento de problemas à medida que eles surgem.
Está tudo configurado para a sua plataforma de newsletter. Agora é hora de ver como funciona. Para iniciar o aplicativo Flask, navegue até o diretório do projeto no terminal e execute o seguinte comando:
1 flask --app app run
Em outra janela de terminal, execute o seguinte comando para iniciar o celery worker:
1 celery -A app.celery worker --loglevel=info
Para acessar sua plataforma de boletim informativo, navegue até localhost:5000 no seu navegador. Você verá a página de destino inicial, conforme representado abaixo:
Para funções administrativas, visite a página de administração no localhost:5000/admin. A página deve ficar assim:
Para testar seu aplicativo, inscreva-se na página inicial. Você pode adicionar quantos assinantes quiser. Após a assinatura bem-sucedida, você verá uma confirmação semelhante a esta:
O formulário será apagado e uma mensagem de sucesso será exibida.
Para verificar os dados da assinatura, use os seguintes comandos do MongoDB em seu terminal:
1 mongosh 2 show dbs 3 use newsletter 4 show collections
Você verá que um banco de dados chamado newsletter foi criado junto com uma coleção deassinantes que contém as entradas de assinatura:
1 Current Mongosh Log ID: 666151bb5bb9f923c2a26a12 2 Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.2.6 3 Using MongoDB: 7.0.11 4 Using Mongosh: 2.2.6 5 6 For mongosh info see: https://docs.mongodb.com/mongodb-shell/ 7 8 ------ 9 The server generated these startup warnings when booting 10 2024-06-06T06:44:55.413+01:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem 11 2024-06-06T06:44:56.369+01:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted 12 2024-06-06T06:44:56.369+01:00: vm.max_map_count is too low 13 ------ 14 15 test> show dbs 16 admin 40.00 KiB 17 config 60.00 KiB 18 local 72.00 KiB 19 newsletter 40.00 KiB 20 test> use newsletter 21 switched to db newsletter 22 newsletter> show collections 23 subscribers 24 newsletter> db.subscribers.find().pretty() 25 [ 26 { 27 _id: ObjectId('66614cf25c0255f4a797fe97'), 28 firstname: 'Mercy', 29 lastname: 'Udoh', 30 email: 'mercybassey683@gmail.com', 31 subscribed: true 32 } 33 ... 34 ] 35 newsletter>
Em seguida, para enviar e-mails em lote, acesse sua página de administração em localhost:5000/admin e envie um boletim informativo. O backend do Celery deve registrar o seguinte após o envio bem-sucedido do e-mail:
1 [2024-06-06 13:34:37,304: WARNING/ForkPoolWorker-4] Email sent 2 [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'}
Confirme a criação da collection
deliveries
junto comsubscribers
no seu MongoDB database:1 newsletter> show collections 2 deliveries 3 subscribers 4 newsletter>
Para revisar o conteúdo da coleção
deliveries
e verificar os detalhes dos e-mails enviados, use o seguinte comando em seu shell do MongoDB:1 db.deliveries.find().pretty()
Esse comando exibirá os registros na collectionentregas de maneira formatada, permitindo que você analise facilmente cada entrada. Você deverá ver dados semelhantes ao seguinte resultado, que inclui detalhes como endereço de e-mail, título do boletim informativo, conteúdo do corpo e o registro de data e hora de quando cada e-mail foi enviado.
1 newsletter> db.deliveries.find().pretty() 2 [ 3 { 4 _id: ObjectId('6661acdd5d0b93accd9fba1e'), 5 email: 'mercybassey683@gmail.com', 6 title: 'Green Thumbs Monthly: June Garden Tips & Upcoming Events', 7 body: 'Dear Green Thumbs Members,\r\n' + 8 '\r\n' + 9 "Welcome to your June edition of the Green Thumbs Monthly! As the days grow longer and the soil warms, it’s the perfect time to dive deep into the joys of summer gardening. Here's what's inside this issue:\r\n" + 10 '\r\n' + 11 '1. Member Spotlight:\r\n' + 12 'This month, we’re featuring Jane Doe, who has transformed her backyard into a vibrant oasis of native plants and vegetables. ', 13 delivered_at: ISODate('2024-06-06T12:34:37.237Z') 14 } 15 ] 16 newsletter>
Isso garante que você possa acompanhar o sucesso e o conteúdo de cada envio dentro do seu sistema de boletins informativos.
E aqui está! Você criou uma plataforma de boletim informativo poderosa e interativa. Esse projeto não só permitiu que você aprofundasse sua compreensão de Python, JavaScript, Flask e MongoDB, mas também deu uma ideia de como essas tecnologias se entrelaçam para criar um aplicativo web funcional.
Ao admirar sua criação, lembre-se de que isso é apenas o começo. Você pode continuar aprimorando essa plataforma com mais recursos, como respostas automatizadas, integração analítica para acompanhar o envolvimento do assinante e modelos de e-mail personalizáveis. A vantagem de criar é que ela nunca está realmente terminada. Sempre há algo mais a adicionar, melhorar e renovar. Então, continue explorando, continue aprendendo e, o mais importante, continue criando.
Quer continuar a conversa? Se você tiver dúvidas ou quiser se conectar com outras pessoas que estão construindo coisas legais com o MongoDB, acesse nossa Comunidade de desenvolvedores a seguir.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.