In our daily lives, we continuously send and receive emails, create calendar events, update contacts, and more. Webhooks offer an ideal solution for receiving notifications when any of these events occur. With webhooks, you don’t have to constantly request information; instead, you can simply wait for notifications to be delivered to your application. While you typically need an external server to host your webhook-enabled application, the Nylas Python SDK makes it easy to test local webhooks on your machine.
As we’ve seen, we can employ a web server to test our webhooks, as demonstrated using Ruby, Python, and PHP. Additionally, we can test webhooks locally using the Nylas CLI.
In Episode 26 of Coding with Nylas, titled Exploring Nylas’ Webhook Utilities we received a glimpse of using the NodeJS SDK to test webhooks locally.
Now, let’s delve into our main focus: demonstrating how to use another one of our SDKs to test webhooks locally—the Python SDK.
Testing anything on our local machine is advantageous because, if something goes wrong, we can quickly address it. Testing on a web server can be more complex, requiring the repetition of a lengthy workflow to implement necessary changes.
By testing locally, we can ensure that everything is functioning correctly before deploying it to an external web server.
Typically, we develop web applications using Flask, but this time, we’re opting to create a Desktop application using DearPyGUI.

As we can here, we’re going to have the following information available:
But we also have a BarPlot dashboard showing how many emails were sent and how many were received.
If you already have the Nylas Python SDK installed and your Python environment configured, feel free to continue reading the blog.
However, if you haven’t done so yet, I recommend checking out the post How to Send Emails with the Nylas Python SDK, where the basic setup is clearly explained.
The installation process is straightforward. Simply type the following command in our terminal window:
$ pip3 install dearpygui
First, create a folder named Local_Webhooks. Inside this folder, create another one named fonts.
Download the Roboto Font Family and move the file Roboto-Regular.ttf into the fonts folder.
Now, let’s create a file named local_webhooks.py in the root folder:
# Import your dependencies
import dearpygui.dearpygui as dpg
from nylas import APIClient
from nylas.services.tunnel import open_webhook_tunnel
from nylas.client.restful_models import Webhook
import os
import datetime
from dotenv import load_dotenv
# Load your env variables
load_dotenv()
# Create the GUI Context
dpg.create_context()
# Register our font and size
with dpg.font_registry():
default_font = dpg.add_font("fonts/Roboto-Regular.ttf", 20)
# Initialize an instance of the Nylas SDK using the client credentials
nylas = APIClient(
os.environ.get("CLIENT_ID"),
os.environ.get("CLIENT_SECRET"),
)
# Initialize an instance of the Nylas SDK using the client credentials
nylas_mail = APIClient(
os.environ.get("CLIENT_ID"),
os.environ.get("CLIENT_SECRET"),
os.environ.get("ACCESS_TOKEN")
)
# Variables to hold our information
webhooks_list = []
sent = [0]
received = [0]
# Main function to run our Webhooks
def run_webhook():
# When a webhook notification gets triggered
def on_message(delta):
# We're only checking for message created or message updated
if delta["type"] == Webhook.Trigger.MESSAGE_CREATED or
delta["type"] == Webhook.Trigger.MESSAGE_UPDATED:
# With the id, get the message details
message = nylas_mail.messages.get(delta["object_data"]["id"])
# Fill our array variable with all needed information
webhooks_list.append([delta["object_data"]["id"],
datetime.datetime.fromtimestamp(delta["date"]).strftime('%Y-%m-%d %H:%M:%S'),
message.from_[0]["email"],message.to[0]["email"],message.subject,delta["type"]])
# Only for message created
if delta["type"] == Webhook.Trigger.MESSAGE_CREATED:
# Determine whether we're are sending or receiving emails
if message.to[0]["email"] == os.environ.get("EMAIL_ID"):
received[0] += 1
else:
sent[0] += 1
# Update the BarPlot
dpg.set_value('sent', [[6], sent])
dpg.set_value('received', [[16], received])
dpg.fit_axis_data("yaxis_tag")
# Delete the table in order to recreate it
dpg.delete_item("table")
# Specify the table again
with dpg.table(header_row=True, tag="table", parent="window"):
dpg.add_table_column(label="Id")
dpg.add_table_column(label="Date")
dpg.add_table_column(label="Email From")
dpg.add_table_column(label="Email To")
dpg.add_table_column(label="Title")
dpg.add_table_column(label="Type")
# Read our array and put the information on the table
for hook in webhooks_list:
with dpg.table_row():
dpg.add_text(hook[0])
dpg.add_text(hook[1])
dpg.add_text(hook[2])
dpg.add_text(hook[3])
dpg.add_text(hook[4])
dpg.add_text(hook[5])
# When the webhooks get connected
def on_open(ws):
print("opened")
# Do we have any errors?
def on_error(ws, err):
print("Error found")
print(err)
# Open the webhook tunnel and wait for incoming notifications
open_webhook_tunnel(
nylas, {"on_message": on_message, "on_open": on_open, "on_error": on_error}
)
# Create the application window
with dpg.window(label="Webhooks Table", tag="window",
pos=(0,0), width=1100, height=300, no_resize = True, no_close = True, no_collapse = True):
# Bind our font, so that we can use it
dpg.bind_font(default_font)
# Create the table
with dpg.table(header_row=True, tag="table"):
# Define the columns
dpg.add_table_column(label="Id")
dpg.add_table_column(label="Date")
dpg.add_table_column(label="Email From")
dpg.add_table_column(label="Email To")
dpg.add_table_column(label="Title")
dpg.add_table_column(label="Type")
# Create the BarPlot
with dpg.window(label="", width=500, height=300, pos=(300,301), no_title_bar = True):
with dpg.plot(height=-1, width=-1, no_title = True):
# Add legend
dpg.add_plot_legend(location = 1)
# Define the BarPlot characteristics and initial data
dpg.add_plot_axis(dpg.mvXAxis, label="", no_gridlines=True, tag="x_axis",no_tick_labels = True)
dpg.set_axis_limits(dpg.last_item(), 1, 20)
dpg.add_plot_axis(dpg.mvYAxis, label="", tag="yaxis_tag")
dpg.set_axis_limits_auto("yaxis_tag")
dpg.add_bar_series([6], sent, label="Sent", weight=1, parent="yaxis_tag", tag = "sent")
dpg.add_bar_series([16], received, label="Received", weight=1, parent="yaxis_tag", tag = "received")
# Call the webhook function
run_webhook()
# Define the application viewport
dpg.create_viewport(title='Webhooks Monitor', width=1100, height=600)
# Initialize the application
dpg.setup_dearpygui()
# Display the viewport
dpg.show_viewport()
# Start our application
dpg.start_dearpygui()
# Destroy the context when the application ends
dpg.destroy_context()
To execute our script, all we need to do is run it like this:
$ python3 local_webhook.py
Testing local webhooks with Python saves you a lot of time and helps you to prevent errors.
If you want to learn more about Webhooks, go to our documentation.
You can sign up for Nylas for free and start building!
Don’t miss the action, join our LiveStream Coding with Nylas: