- Products
- Solutions Use casesBy industry
- Developers
- Resources Connect
- Pricing
Python full-stack frameworks are becoming a critical part of today’s development, as they allow developers to create backend and frontend applications without needing the knowledge of JavaScript, CSS and so on, so we will develop an application to send an email using four of the most popular frameworks.
Continue with the blog if you already have the Nylas Python SDK installed and your Python environment configured. Also, you can check the Nylas Quickstart Guides.
Otherwise, I recommend reading the post How to Send Emails with the Nylas Python SDK, which covers the basic setup. I will teach you how to send an email although without using a full-stack framework.
Let’s design how our application will look like. We will need a combo box for the recipient, three text inputs for the name, email and subject, a textarea for the body and a submit button. The combo box will get the contacts list using the Nylas Contacts API. Once we select a contact, its name and email will be populated into the name and email fields, although we can specify the name and email manually. When building this with a full-stack framework, we will be able to send an email with almost no effort.
NiceGUI first version was released on May 14, 2021, and it’s currently on version 1.3.4.
It uses Vue and Quasar for the frontend, and it’s built on top of FastAPI.
The learning curve is gentle, and it’s overall user-friendly for beginners. The documentation is complete and useful.
Once installed, we’re ready to go. Let’s create a file called email_sender.py with the following code:
# Import your dependencies from dotenv import load_dotenv import os from nylas import APIClient # type: ignore from nicegui import ui # Load your env variables load_dotenv() # Initialize an instance of the Nylas SDK using the client credentials nylas = APIClient( os.environ.get("CLIENT_ID"), os.environ.get("CLIENT_SECRET"), os.environ.get("ACCESS_TOKEN"), ) # Dictionary to hold all email information contact_info = {'recipient':'','name':'','email':'','subject':'', 'body':''} # List to hold all contacts contacts_list = [] emails_list = {} # Function to send the email def send_email(): # Create the draft draft = nylas.drafts.create() # Assign subject, body and name and email of recipient draft.subject = contact_info['subject'] draft.body = contact_info['body'] draft.to = [{"name": f"{contact_info['name']}", "email": f"{contact_info['email']}"}] try: # Send the email draft.send() ui.notify("Email was sent successfully") except Exception as e: ui.notify(f'An error ocurred: {e}') finally: # Clear all fields recipient.set_value("") name.set_value("") email.set_value("") subject.set_value("") body.set_value("") # Update the dictionary with the updated values def update_field(field, value): # If we choose a recipient if field == 'recipient' and value != '': # Get the name and email from the contact contact_info[f'{field}'] = value contact_info['name'] = field contact_info['email'] = emails_list[value] # Update the fields email.set_value(emails_list[value]) name.set_value(value) else: # Update any other value contact_info[f'{field}'] = value # Grab the first 5 contacts from the specified group contacts = nylas.contacts.where(source = 'address_book', limit = 5, group = "517v55haghlcvnuu7lcm4f7k8") # Loop all contacts and get the Id and Full Name for contact in contacts: contacts_list.append(contact.given_name + " " + contact.surname) emails_list[f'{contact.given_name + " " + contact.surname}'] = list(contact.emails.values())[0][0] # Main layout with everything centered with ui.column().classes('w-full items-center'): # Set application title, list of contacts, name, email and email body ui.label('Email Sender').tailwind.font_weight('black').font_size('6xl').text_color('blue-700') recipient = ui.select(label = "Recipient", options=contacts_list, with_input=True, on_change = lambda e: update_field('recipient', e.value)).classes('w-50') name = ui.input(label='Name', placeholder='Name', on_change = lambda e: update_field('name', e.value)).classes('w-64') email = ui.input(label='Email', placeholder='Email', on_change = lambda e: update_field('email', e.value)).classes('w-64') subject = ui.input(label='Subject', placeholder='Email Subject', on_change = lambda e: update_field('subject', e.value)).classes('w-64') body = ui.textarea(label='Body', placeholder='Email Body', on_change = lambda e: update_field('body', e.value)).classes('w-64') # Submit button ui.button('Send Email', on_click=send_email) # Run our application ui.run(title = 'Email Sender')
To run our application, we need to type the following on our terminal window:
$ python3 email_sender.py
The browser will open automatically:
Here we can fill in the details and send our email:
After we hit send, we will get a notification at the bottom of the screen, letting us know if the email as sent or not:
And we can check our mailbox just to confirm:
Reflex was initially called Pynecone. Its first version was released on November 24, 2022, and it’s currently on version 0.2.0
It uses React for the frontend and Bun as the JavaScript runtime.
The learning curve is not so gentle, but still easier to grasp.
It uses a State concept that can be a little complicated sometimes.
We can install it by typing the following command in our terminal window:
$ pip3 install reflex
We’re going to create a folder called reflex_send_email using the following command in the terminal:
$ mkdir reflex_send_email
Once we are inside the folder, we need to initialize our Reflex application:
$ reflex init
This will generate some files and also another folder called reflex_send_email. Inside this new folder, we will find a file called reflex_send_email.py, this is the file that we need to update:
# Import your dependencies from rxconfig import config import reflex as rx from dotenv import load_dotenv import os from nylas import APIClient # type: ignore from typing import List # Load the app configuration filename = f"{config.app_name}/{config.app_name}.py" # This class represents the State of the app # and hold all the important functions class State(rx.State): # Variables to hold form information recipient : str = "" name : str = "" email : str = "" subject : str = "" body : str = "" message : str = "" # We need methods to update the fields def set_name(self, name: str): self.name = name def set_email(self, email: str): self.email = email def set_body(self, body: str): self.body = body def set_subject(self, subject: str): self.subject = subject def set_email_name(self, name : str): self.name = name self.email = emails_list[name] # When we press submit, we want to get # all the form information def handle_submit(self, form_data: dict): # Create the draft draft = nylas.drafts.create() # Define the subject, body, name and email of recipient draft.subject = form_data['Subject'] draft.body = form_data['Body'] draft.to = [{"name": f"{form_data['Name']}", "email": f"{form_data['Email']}"}] try: # Send the email draft.send() self.message = "Email was sent successfully" except Exception as e: self.message = f'An error ocurred: {e}' finally: self.name = "" self.email = "" self.subject = "" self.body = "" self.recipient = "" # Load your env variables load_dotenv() # Initialize an instance of the Nylas SDK using the client credentials nylas = APIClient( os.environ.get("CLIENT_ID"), os.environ.get("CLIENT_SECRET"), os.environ.get("ACCESS_TOKEN"), ) # Get a list of contacts, from a particular group # limiting to 5 contacts only full_names: List[str] = [] emails_list = {} # Call the contacts endpoint contacts = nylas.contacts.where(source = 'address_book', limit = 5, group = "517v55haghlcvnuu7lcm4f7k8") # Loop the contacts for contact in contacts: # Append them to lists full_names.append(contact.given_name + " " + contact.surname) emails_list[f'{contact.given_name + " " + contact.surname}'] = list(contact.emails.values())[0][0] # This section defines the UI def index(): return rx.center( rx.vstack( rx.form( rx.heading("Email Sender"), rx.text("Recipient"), rx.select( full_names, placeholder = " ", value = State.recipient, on_change = State.set_email_name, id = "recipient" ), rx.text("Name"), rx.input(value = State.name, on_change = State.set_name, id="Name"), rx.text("Email"), rx.input(value = State.email, on_change = State.set_email, id="Email"), rx.text("Subject"), rx.input(value = State.subject, on_change = State.set_subject, id="Subject"), rx.text("Body"), rx.text_area(value = State.body, on_change = State.set_body, id="Body"), rx.button("Send Email", type_="submit", color_scheme="red", size="md"), width="100%", on_submit=State.handle_submit, ), # This will work as our notification system rx.input(value = State.message, bg="#68D391"), ), ) # Add state and page to the app. app = rx.App(state=State) app.add_page(index) app.compile()
To be able to run our application, we need to be in the root folder and type the following on the terminal:
$ reflex run
Our application will run on port 3000, so we need to open our favourite browser:
And start populating the fields:
After we hit send, we will get a notification at the bottom of the screen, letting us know if the email as sent or not:
And we can check our mailbox just to confirm:
Solara first version was released on April 4, 2022, and it’s currently on version 1.18.0
It uses React for the frontend. It can be run on web apps or in Jupyter Notebooks.
The learning curve is somehow easy, although its documentation is not the best. I needed to dig into their Github repository more than once.
Still, a great user experience.
We can install it by typing the following command in our terminal window:
$ pip3 install solara
Once installed, we’re ready to go. Let’s create a file called email_sender.py with the following code:
# Import your dependencies import solara from solara.alias import rv from dotenv import load_dotenv import os from nylas import APIClient # type: ignore # Load your env variables load_dotenv() # Initialize an instance of the Nylas SDK using the client credentials nylas = APIClient( os.environ.get("CLIENT_ID"), os.environ.get("CLIENT_SECRET"), os.environ.get("ACCESS_TOKEN"), ) # List to hold all contacts contacts_list = [] emails_list = {} # Reactive components recipient = solara.reactive("") name = solara.reactive("") email = solara.reactive("") subject = solara.reactive("") message = solara.reactive("") name_txt = "" email_txt = "" # Grab the first 5 contacts from the specified group contacts = nylas.contacts.where(source = 'address_book', limit = 5, group = "517v55haghlcvnuu7lcm4f7k8") # Loop all contacts and get the Id and Full Name for contact in contacts: contacts_list.append(contact.given_name + " " + contact.surname) emails_list[f'{contact.given_name + " " + contact.surname}'] = list(contact.emails.values())[0][0] # Placeholder for the email body markdown_initial = """ """.strip() @solara.component def Page(): # When we select a contact, fill in the details def fill_details(foo): name.set(recipient.value) email.set(emails_list.get(recipient.value)) def send_email(): draft = nylas.drafts.create() draft.subject = str(subject).strip("'") draft.body = str(markdown_text).strip("'") name_txt = str(name).strip("'") email_txt = str(email).strip("'") draft.to = [{"name": f"{name_txt}", "email": f"{email_txt}"}] try: draft.send() message.set("Email was sent successfully") except Exception as e: message.set(f'An error ocurred: {e}') finally: name.set("") email.set("") subject.set("") recipient.set("") set_markdown_text("") # Define the markdown to be used as the email body markdown_text, set_markdown_text = solara.use_state(markdown_initial) # This section is for the UI with solara.Card("") as main: with solara.Column(gap="12px", align="center"): solara.Markdown(r'''# Email Sender''') solara.Select(label="Recipient", value = recipient, values=contacts_list, on_value=fill_details) solara.InputText(label="Name", value=name) solara.InputText(label="Email", value=email) solara.InputText(label="Subject", value=subject) rv.Textarea(label = "Body", v_model=markdown_text, on_v_model=set_markdown_text, rows=5) solara.Button(label="Send Email", on_click=send_email) # This will work as our notification system solara.Success( f"{message}", text=False, dense=True, outlined=True, icon=False, ) return main
To be able to run our application, we need to be in the root folder and type the following on the terminal:
$ solara run email_sender.py
The browser will open automatically:
Here we can fill in the details and send our email:
After we hit send, we will get a notification at the bottom of the screen, letting us know if the email as sent or not:
And we can check our mailbox just to confirm:
PyWebIO first version was released on April 30, 2020, and it’s currently on version 1.8.2
It seems it relies on Python, HTML and JS. So no JavaScript frameworks are involved.
The learning curve is somehow easy, although its documentation is not bad, not everything is that easy to find. However, a few web searches were more than enough to help me.
A surprisingly great experience.
We can install it by typing the following command in our terminal window:
$ pip3 install pywebio
Once installed, we’re ready to go. Let’s create a file called pywebio_email_sender.py with the following code:
# Import your dependencies from dotenv import load_dotenv import os from nylas import APIClient # type: ignore from pywebio.input import * from pywebio.output import * from pywebio import start_server # Load your env variables load_dotenv() # Initialize an instance of the Nylas SDK using the client credentials nylas = APIClient( os.environ.get("CLIENT_ID"), os.environ.get("CLIENT_SECRET"), os.environ.get("ACCESS_TOKEN"), ) # List to hold all contacts contacts_list = [] emails_list = {} # Grab the first 5 contacts from the specified group contacts = nylas.contacts.where(source = 'address_book', limit = 5, group = "517v55haghlcvnuu7lcm4f7k8") # Loop all contacts and get the Id and Full Name contacts_list.append("") emails_list[""] = "" for contact in contacts: contacts_list.append(contact.given_name + " " + contact.surname) emails_list[f'{contact.given_name + " " + contact.surname}'] = list(contact.emails.values())[0][0] # Update the name and email when selecting the combo box def set_name(contact): input_update('email', value = emails_list[contact]) input_update('name', value = contact) # Our main function def main(): # Run while the application is running while True: # This is our UI data = input_group( "Email Sender", [ select('Recipient', options = contacts_list, name="recipient", onchange=set_name), input("Name", name="name", type=TEXT), input("Email", name="email", type=TEXT), input("Subject", name="subject", type=TEXT), textarea('Body', name="body", rows=3, placeholder=''), ], ) # This happens when we click on the "Submit" button draft = nylas.drafts.create() # Populate the email draft.subject = data["subject"] draft.body = data["body"] name_txt = data["name"] email_txt = data["email"] draft.to = [{"name": f"{name_txt}", "email": f"{email_txt}"}] try: # Send the email and get notified draft.send() toast('Email was sent successfully', position='right', color='#2188ff', duration=0) except Exception as e: toast(f'An error ocurred: {e}', position='right', color='#2188ff', duration=0) if __name__ == '__main__': # Start the server start_server(main, port=8080, debug=True)
To be able to run our application, we need to be in the root folder and type the following on the terminal:
$ python3 pywebio_email_sender.py
We need to open our favourite browser on port 8080:
Here we can fill in the details and send our email:
After we hit send, we will get a notification at the bottom of the screen, letting us know if the email as sent or not:
And we can check our mailbox just to confirm:
Taipy first version was released on April 7, 2022, and it’s currently on version 3.0.0
It uses mui.com, which is a set of React UI tools.
The learning curve is strange, and the documentation is not easy to navigate, although getting it to work is surprisingly fast.
A great experience and a way different way of working.
We can install it by typing the following command in our terminal window:
$ pip3 install taipy
Once installed, we’re ready to go. Let’s create a file called taipy_email_sender.py with the following code:
# Import your dependencies from dotenv import load_dotenv import os from nylas import APIClient # type: ignore from taipy.gui import Gui , notify # Load your env variables load_dotenv() # Initialize an instance of the Nylas SDK using the client credentials nylas = APIClient( os.environ.get("CLIENT_ID"), os.environ.get("CLIENT_SECRET"), os.environ.get("ACCESS_TOKEN"), ) # List to hold all contacts contacts_list = [] emails_list = {} # Grab the first 5 contacts from the specified group contacts = nylas.contacts.where(source = 'address_book', limit = 5, group = "517v55haghlcvnuu7lcm4f7k8") # Loop all contacts and get the Id and Full Name for contact in contacts: contacts_list.append(contact.given_name + " " + contact.surname) emails_list[f'{contact.given_name + " " + contact.surname}'] = list(contact.emails.values())[0][0] # Global variables for the state name = "" email = "" subject = "" body = "" # Definition of the page page = """ # Email Sender Recipient <|{contact}|selector|lov={contacts_list}|dropdown|> Name <|{name}|input|> Email <|{email}|input|> Subject <|{subject}|input|> Body <|{body}|input|multiline=true|> <|Send Email|button|on_action=on_button_action|> """ # When we press the send button def on_button_action(state): # Create the draft draft = nylas.drafts.create() # Assign subject, body and name and email of recipient draft.subject = state.subject draft.body = state.body draft.to = [{"name": f"{state.name}", "email": f"{state.email}"}] try: # Send the email notify(state, 'info', 'Email was sent successfully') draft.send() except Exception as e: notify(state, 'info', 'An error ocurred') finally: # Clear all fields state.subject = "" state.body = "" state.name = "" state.email = "" state.contact = "" # When we select the contact combo box def on_change(state, var_name, var_value): if var_name == "contact": state.name = var_value state.email = emails_list[var_value] return # Run the page Gui(page).run()
In order to apply some CSS, we need to create a file with the same as our application, so taipy_email_sender.css:
:root { height: 200px; display: flex; align-items: center; justify-content: center; }
To be able to run our application, we need to be in the root folder and type the following on the terminal:
$ taipy run taipy_email_sender.py
Our favourite browser will be opened automatically on port 5000:
Here we can fill in the details and send our email:
After we hit send, we will get a notification at the bottom of the screen, letting us know if the email as sent or not:
And we can check our mailbox just to confirm:
We have built the same email sender example using four different Python full-stack frameworks so that you can draw your conclusions on which one suits your project requirements. They all have good and bad things, but we cannot deny they are useful and help speed development.
Do you have any favourite full-stack framework that you use to send an email? Share it with us, we would love to see it and explore it.
To learn more about our Email APIs, visit our documentation Email API Overview.
You can sign up for Nylas for free and start building!
Blag aka Alvaro Tejada Galindo is a Senior Developer Advocate at Nylas. He loves learning about programming and sharing knowledge with the community. When he’s not coding, he’s spending time with his wife, daughter and son. He loves Punk Music and reading all sorts of books.