Back to main menu

Building transactional email workflows for password resets with Mailgun’s API

Struggling with sending secure password reset emails? This hands-on guide walks you through building a reliable, automated email workflow using Mailgun’s API and FastAPI.…

PUBLISHED ON

PUBLISHED ON

Transactional emails are automated emails triggered by user actions on a website, app, or service. Unlike marketing emails, which promote products or services, transactional emails provide essential, often real-time information.

Transactional email workflows take this further by automating a sequence of emails based on user actions to ensure timely communication and a smooth user experience. Companies rely on services like Mailgun for transactional emails because they're prompt, relevant, and triggered by immediate user actions. For example, the workflow allows a user to quickly reset their password and regain access to their account.

In this tutorial, you'll learn how to build a transactional email workflow for password resets with Mailgun's API.

Setting up a Mailgun account

If you don't already have a Mailgun account, the first thing you need to do is create one. Make sure to check the email associated with your Mailgun account and verify your account:

Account Verification Image

Next, input your phone number and the provided authorization code to activate your account:

Account Verification Phone Number image

Once your Mailgun account is set up, it's time to obtain an API key to start using the service.

Obtaining an API key

For your application to interact with Mailgun's services, it needs to be authenticated via an API key. To get your API key, navigate to the Mailgun dashboard and select Get started on the left to view a Get started guide:

API Get Started Guide Image

Click the Get started button under Create an API Key. Then, provide a description that properly describes the API's key purpose. For example, if the API key is for user authentication processes, you can name it something like user_authentication and click Create Key:

Create New API Key Image

Make sure to copy and keep this key somewhere safe, as this is the only time the key will be displayed:

New API Key Image

Building the application interface using FastAPI

To build the application interface that powers the email workflow, the first thing you need to do is install the necessary libraries. Before you do, create a project directory by running mkdir my_fastapi_app and launch a virtual environment in the directory.

Then, install the necessary libraries with the following command:

pip install fastapi jinja2 requests uvicorn python-multipart

Here, you install:

  • fastapi, which serves as the main backend framework

  • jinja2, which serves your frontend templates

  • requests, which sends HTTP requests to the Mailgun API

While FastAPI is primarily for building APIs, adding the jinja2 library allows for full-stack development – but it requires proper directory setup. Your project structure should follow this format:

my_fastapi_app/ │── main.py # Main FastAPI application file │── users.json # JSON file storing user data │── templates/ # HTML templates folder │ ├── login.html # Login page │ ├── home.html # Home page │ ├── passwordReset.html # Password reset page │── static/ # Static files folder │ ├── styles.css # Styles for the login.html and passwordReset.html files

You can find all the code for this tutorial in this GitHub repository.

With your project structure in place, you can either copy and paste the code into the respective files or clone the GitHub repository above with the following command:

git clone https://github.com/EphraimX/building-transactional-email-workflows-for-password-resets-with-mailgun-api.git

Let's take a look at the first section of the main.py file. This file is where all the magic happens, as it connects the frontend and backend operations:

In this code, the app handles authentication by serving login and password reset pages while verifying credentials in users.json. The app initializes FastAPI, configures templates, and defines a loginData model for validation. The /login and /passwordResetView/ routes serve their respective pages, while /home verifies credentials, redirecting valid users or displaying errors. The password reset function generates a unique link using uuid and sends it via Mailgun's API.

To test this out, open your makeshift database (users.json) and paste the following:

You should also authorize these email addresses via the Mailgun dashboard if you're using a sandbox domain.

Start your application by running the command uvicorn main:app --reload. Then, head over to http://localhost:8000/login, where you should see this:

API Login Image

If you attempt to log in with any of the credentials in the users.json file, you'll be taken to the home page:

Successful API Login Image

If you input the wrong login information, you'll see the following:

Unsuccessful API Login Image

Setting up a connection to Mailgun

To send emails using Mailgun, you need to establish a connection between your application and Mailgun's email service.

To do so, open main.py and paste the following code, replacing <SANDBOX_URL>, <RECIPIENT_NAME>, and <RECIPIENT_EMAIL> with valid values:

For testing purposes, pass your API key directly when calling the function:

send_simple_message("your-api-key-here")

Run the script by executing the following:

python main.py

If successful, the function will print a response similar to this:

{ "id": "<MESSAGE_ID>", "message": "Queued. Thank you." }

This confirms that the email request has been successfully queued by Mailgun.

Designing and setting up the email template

To work on the password reset logic, you need to design the template for the email that's sent to the user. With Mailgun, there are two ways to design an email: HTML or Mailgun's drag-and-drop template builder. You'll use the HTML approach here.

To begin the design, go to your Mailgun dashboard and navigate to Send > Sending > Templates:

Templates Image

Next, click Create message template, select the option to code it in HTML, and click the Blank template:

Blank Option image

Fill in the template form with the name, description, and details of the email:

Template Details image

Then, scroll down to the Editor tab and copy and paste the code from the email_template.html file:

Template Editor Image

When you select the Test Data tab, you'll see two dynamic variables: username and reset_link.

Select the Preview tab to see the template:

Reset Password Image

Finally, click the Create button to create it.

Implementing the email sending functionality

Once your email template is ready, it's time to build out the email sending functionality. Open the main.py file and paste the following code:

In this code, the reset_password function (@app.post("/resetPassword/")) processes password reset requests by checking if the submitted email exists in the users.json database. If found, it generates a unique reset link using generate_password_reset_link(email_address) and sends the reset email via send_password_reset_email(username, email_address, reset_link). The function then returns a success message if the email was sent or displays an error message if not. If no matching email is found, an appropriate error response is provided.

Note: Replace the API_KEY variable with the key to your Mailgun account.

To test the implementation, run uvicorn main:app --reload and open http://localhost:8000/login. Click the Forgot Password? link:

Forgot Password Link Image

Enter an email present in your users.json file and click Reset Password:

Forgot Password Reset Image

If successful, you should be directed back to the login page, where you'll be met with instructions to check your email. You should see the following email in the recipient's email inbox:

Reset Password Request Image

Integrating with application events

Integrating with application events using webhooks allows your system to automatically respond to real-time updates from external services.

A webhook is essentially an HTTP callback. Whenever a specific event occurs in an external application (such as a payment confirmation, user signup, or password reset request), the service sends a request to your predefined webhook URL. This enables seamless automation, reducing the need for manual intervention or periodic polling. By configuring your application to listen for these webhook events, you can trigger relevant actions, such as updating a database, sending notifications, or processing transactions, as soon as the event happens.

To integrate webhooks with Mailgun, you need to create an endpoint. To do that, open the main.py file and paste the following code at the end:

Return to the dashboard and go to Send > Sending > Webhooks:
Add Webhooks Image

Click Add webhook in the top-right corner. In the drop-down list of event types, select Delivered Messages, and in the URL field, input the route to your webhook URL. In this case, it's https://<YOUR_DOMAIN>/webhooks/password-reset. When you're finished, click Create webhook:

New Webhook Image

Test the webhook. Your result should look like this:

Test webhook Image

On the server side, you should get the following message:

Password reset email clicked: {'signature': {'token': '41929b08bb287b8a0b157f7834844b6bc483b7b090692a2b15', 'timestamp': '1739785355', 'signature': '117f70dcf985c72df30c07b02898dd458d1cbbad29d0457ccee8c4497f89c5ac'}, 'event-data': {'id': 'CPgfbmQMTCKtHW6uIWtuVe', 'timestamp': 1521472262.908181, 'log-level': 'info', 'event': 'delivered', 'delivery-status': {'tls': True, 'mx-host': 'smtp-in.example.com', 'code': 250, 'description': '', 'session-seconds': 0.4331989288330078, 'utf8': True, 'attempt-no': 1, 'message': 'OK', 'certificate-verified': True}, 'flags': {'is-routed': False, 'is-authenticated': True, 'is-system-test': False, 'is-test-mode': False}, 'envelope': {'transport': 'smtp', 'sender': 'bob@sandbox9199067bcb654265aae9ce9e308b6150.mailgun.org', 'sending-ip': '209.61.154.250', 'targets': 'alice@example.com'}, 'message': {'headers': {'to': 'Alice <alice@example.com>', 'message-id': '20130503182626.18666.16540@sandbox9199067bcb654265aae9ce9e308b6150.mailgun.org', 'from': 'Bob <bob@sandbox9199067bcb654265aae9ce9e308b6150.mailgun.org>', 'subject': 'Test delivered webhook'}, 'attachments': [], 'size': 111}, 'recipient': 'alice@example.com', 'recipient-domain': 'example.com', 'storage': {'url': 'https://se.api.mailgun.net/v3/domains/sandbox9199067bcb654265aae9ce9e308b6150.mailgun.org/messages/message_key', 'key': 'message_key'}, 'campaigns': [], 'tags': ['my_tag_1', 'my_tag_2'], 'user-variables': {'my_var_1': 'Mailgun Variable #1', 'my-var-2': 'awesome'}}}

This may change depending on the email being sent.

Monitoring and managing emails

Peter Drucker, a famous management consultant, once said:

If you can't measure it, you can't improve it.

In line with this, Mailgun provides tools to check the performance of sent emails. For example, the Send > Sending > Analytics page helps measure what percentage of emails are being delivered, opened, and clicked:

Analytics Image

On the Send > Reporting > Metrics page, you can get detailed information about how your emails are performing:

Metrics image

You can also choose the metrics you wish to see over a given period:

Customized Metrics Image

Mailgun also provides you with logs in case you want to dig deeper into delivered events and investigate failures when they occur:

Logs Image

Lastly, Mailgun provides a bounce classification to see how many of your emails don't go through. It also lets you know how many of those bounces are critical:

Bounce Classification Image

Wrapping up

In this tutorial, you learned how to build a complete transactional email workflow for password resets using Mailgun's API. After setting up a Mailgun account and obtaining an API key, you built an application interface using FastAPI. You then designed and configured an email template, implemented email sending functionality, and integrated webhooks for real-time event tracking.

Transactional email operations are critical in providing a seamless and secure user experience, especially for password resets. Mailgun can help you automate this process, improving security and productivity while eliminating manual intervention. Implementing this approach in your projects will not only increase customer satisfaction but also help maintain a dependable authentication system.

Sign Up

It's easy to get started. And it's free.

See what you can accomplish with the world’s best email delivery platform.

Related readings

Introducing Mailgun’s open-source MCP server

Accessing email data just got easier. With Mailgun’s open-source MCP server, developers can query email performance metrics using natural language—no dashboards, no complex API calls. Built on Model Context Protocol (MCP), this solution makes AI-powered email analytics...

Read More

The 5 best email API services in 2025

In 2025, email APIs are critical for businesses aiming to automate large-scale communications while ensuring top-notch deliverability and compliance. Developers and marketers alike need solutions with reliable infrastructure, developer-friendly tools, and integrations to support...

Read More

The best email APIs in-depth review and comparison

In 2025, email APIs have become indispensable for businesses looking to streamline their communication processes. These APIs not only automate sending and tracking emails but also ensure high deliverability and compliance with global standards. Whether you're a developer or marketer, the right email API can significantly...

Read More

Popular posts

Email inbox.

Email

5 min

Build Laravel 11 email authentication with Mailgun and Digital Ocean

Read More

Mailgun statistics.

Product

4 min

Sending email using the Mailgun PHP API

Read More

Statistics on deliverability.

Deliverability

5 min

Here’s everything you need to know about DNS blocklists

Read More

See what you can accomplish with the world's best email delivery platform. It's easy to get started.Let's get sending
CTA icon