How to Send Email Using Python FastAPI
Let’s start with an introduction about FastAPI before we jump into the main topic. What is FastAPI?
Directly taken from the official documentation:
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
FastAPI has gained a lot of popularity these days because of its speed and easy to set up. It’s probably still debatable to decide which one is better between FastAPI, Flask (in addition to new Flask 2.0), and Django. But in my opinion, it goes back to our use cases. You can read the detail here https://www.section.io/engineering-education/choosing-between-django-flask-and-fastapi/.
Jump to the main topic, let’s create a simple app to send email using FastAPI in two ways, with and without background task.
Before that
In this article, we will use Gmail account to send email and to make sure everything is working properly, you’ll need a Gmail account to do so. Make sure you set Allow less secure apps
to On
, in your google account settings. This is how you can do that:
- Click
manage your Google account
on your account icon (on top right corner).
2. Go to the security tab.

3. You’ll find a section on this page, to allow less secure apps. (here, I have set it on)

4. Turn this setting on.
This won’t work if your account has two-factor authentication enabled. The choices are you can create a separate account or create application-specific passwords.
If you still get authentication errors, you can try this:
- Display unlock captcha. (https://accounts.google.com/DisplayUnlockCaptcha)
- Enable IMAP access. (https://mail.google.com/mail/#settings/fwdandpop)
Create The App
Configure virtual environment
To isolate the environment for this app, we have to use a virtual environment, in this case, I will use pipenv
to manage virtual environment.
pipenv shell
This command will spawn a shell within a virtual environment and generate Pipfile
. Then, we can install the dependencies we need.
pipenv install fastapi fastapi-mail uvicorn python-dotenv
Create a main.py
file and put some template code in there.
import uvicorn
from fastapi import FastAPI, BackgroundTasks
from send_email import send_email_background, send_email_asyncapp = FastAPI(title='How to Send Email')@app.get('/')
def index():
return 'Hello World'if __name__ == '__main__':
uvicorn.run('main:app', reload=True)
To run the app, you can type the command python main.py
. This command will launch the server, then you can look at the documentation generated by FastAPI by going to http://localhost:8000/docs.
Nice…
Now, create .env
file to store sensitive data.
MAIL_USERNAME=<GMAIL_USERNAME>
MAIL_PASSWORD=<GMAIL_PASSWORD>
MAIL_FROM=<SENDER_ADDRESS>
MAIL_PORT=587
MAIL_SERVER=smtp.gmail.com
MAIL_FROM_NAME=<TITLE_FOR_MAIL>
Create a file named send_email.py
, then load the .env
.
import os
from fastapi import BackgroundTasks
from fastapi_mail import FastMail, MessageSchema, ConnectionConfigfrom dotenv import load_dotenv
load_dotenv('.env')class Envs:
MAIL_USERNAME = os.getenv('MAIL_USERNAME')
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
MAIL_FROM = os.getenv('MAIL_FROM')
MAIL_PORT = int(os.getenv('MAIL_PORT'))
MAIL_SERVER = os.getenv('MAIL_SERVER')
MAIL_FROM_NAME = os.getenv('MAIN_FROM_NAME')
We have the imports we need and settings (we need this for the FastAPI MAIL connection config). Then write the connection config and the code to send the email.
conf = ConnectionConfig(
MAIL_USERNAME=Envs.MAIL_USERNAME,
MAIL_PASSWORD=Envs.MAIL_PASSWORD,
MAIL_FROM=Envs.MAIL_FROM,
MAIL_PORT=Envs.MAIL_PORT,
MAIL_SERVER=Envs.MAIL_SERVER,
MAIL_FROM_NAME=Envs.MAIL_FROM_NAME,
MAIL_TLS=True,
MAIL_SSL=False,
USE_CREDENTIALS=True,
TEMPLATE_FOLDER='./templates/email'
)
async def send_email_async(subject: str, email_to: str, body: dict):
message = MessageSchema(
subject=subject,
recipients=[email_to],
body=body,
subtype='html',
)
fm = FastMail(conf)
await fm.send_message(message, template_name='email.html')
def send_email_background(background_tasks: BackgroundTasks, subject: str, email_to: str, body: dict):
message = MessageSchema(
subject=subject,
recipients=[email_to],
body=body,
subtype='html',
) fm = FastMail(conf)
background_tasks.add_task(
fm.send_message, message, template_name='email.html')
In this example, there are two functions, one sends the email asynchronously (or like a normal function) and the other sends the email in the background. You’ll notice the difference after we try to use these functions.
Note that, we generate an HTML email using Jinja2 templating engine. So let’s create an HTML file. First, make a templates
folder and create an HTML file named email.html
. This file is used on the connection configuration (TEMPLATE_FOLDER
).
Like any HTML file using Jinja2 engine, we can provide dynamic data in there and Jinja2 will take care of how it will be rendered. We can access it using body.property
pattern.
Note in here we used inline CSS, just like the official documentation of FastAPI-MAIL suggests us.
In sending HTML emails, the CSS expected by mail servers -outlook, google, etc- must be inline CSS.
Create the path operations to send the email.
@app.get('/send-email/asynchronous')
async def send_email_asynchronous():
await send_email_async('Hello World','someemail@gmail.com',
{'title': 'Hello World', 'name': 'John Doe'})
return 'Success'@app.get('/send-email/backgroundtasks')
def send_email_backgroundtasks(background_tasks: BackgroundTasks):
send_email_background(background_tasks, 'Hello World',
'someemail@gmail.com', {'title': 'Hello World', 'name': 'John Doe'})
return 'Success'
Save all the files, and the server will reload. Now, refresh the documentation page.
You’ll see two new endpoints, namely, /send-email/asynchronous
and /send-email/backgroundtasks
. Try both endpoints to see the difference.
When you are calling the server using asynchronous, you’ll see a loading indicator in the documentation, because the application needs time to send the email. But if you use background task, the client doesn't need to wait for the operation to finish. This capability would be useful when we send email or notification to users. Here more about background tasks https://fastapi.tiangolo.com/tutorial/background-tasks/.
This is how the email looks after you send it:

You can find the code for this article here, https://github.com/agusrichard/fastapi-workbook/tree/master/send-email.
I hope this article would be a good resource for you, thank you for reading.