Shiny for Python: Building an email dashboard

Shiny for Python: Building an email dashboard

5 min read

Have you ever used Shiny? Shiny is an R package that allows you to create interactive web applications that can be used as standalone web applications, embedded in R Markdown or in dashboards.

But we’re not here today to talk about R, but to talk about Python. And now Python has access to Shiny, which is wonderful news. By using Shiny for Python, we can create amazing dashboards, using all the power that Python has to offer.

Let’s create an Email Dashboard using Shiny for Python.

What are we going to do today?

  • Is your system ready?
  • Installing additional packages
  • What are we going to build?
  • What does our dashboard look like?
  • Let’s start building

Is your system ready?

If you don’t have the Nylas Python SDK installed and your environment isn’t configured, I would recommend you to read the post How to Send Emails with the Nylas Python SDK where everything is clearly explained.

Installing additional packages

Having the Nylas Python SDK installed and configured is important, but it’s not all we need for sure. We need to install some additional packages, especially Shiny for Python.

$ pip3 install shiny # Shiny for Python
$ pip3 install seaborn # Python data visualization library
$ pip3 install pandas # Data analysis library
$ pip3 install wordcloud # Wordcloud generator
$ pip3 install matplotlib # library for creating static, animated, and interactive visualizations

What are we going to build?

Before moving on with the blog, we should take a look at what we are going to build, which is pretty much, a dashboard. This dashboard will take advantage of the Nylas Python SDK ability to access our email account and read the first 100 emails from our inbox and the first hundred emails from our sent folder.

With this information, we’re going to get the names of the 3 top people that we email from, the names of the top 3 people who we send emails to and finally, we’re going to generate a word cloud, using all the words gathered from the subjects of the emails in our inbox, that is, what are the most important words that people email us about.

What does our dashboard look like?

Here we go:

Shiny for Python dashboard

We have two bar plots and one word cloud. I wished the word cloud image was centered, but haven’t found a way yet.

Let’s start building

First, we need to head to our terminal window and type the following:

$ shiny create mail_dashboard

This will create a file called app.py that we’re going to update with our own source code:

# Load your env variables
from dotenv import load_dotenv
load_dotenv()

# Import your dependencies
from shiny import App, render, ui
from shiny.types import ImgData
import matplotlib.pyplot as plt
import pandas as pd
from nylas import APIClient
import os
import seaborn as sns
from wordcloud import WordCloud

# Initialize your Nylas API client
nylas = APIClient(
    os.environ.get("CLIENT_ID"),
    os.environ.get("CLIENT_SECRET"),
    os.environ.get("ACCESS_TOKEN")
)

# Auxiliar variables
from_messages = []
to_messages = []
text = ""

# Get emails from your inbox folder
f_messages = nylas.messages.where(in_='inbox', limit = 100)
# Get emails from your sent folder
t_messages = nylas.messages.where(in_='sent', limit = 100)

# Loop through your inbox emails
for msg in f_messages:
	# Get the name of the person emailing you
	if(msg["from_"][0]["name"] != ""):
		from_messages.append(msg["from_"][0]["name"].split()[0])
	# Concatate the subjects of all emails
	text = text + " " + msg["subject"]
# Turn the array into a data frame	
f_df = pd.DataFrame(from_messages, columns=['Names'])
# Aggregate values, get the top 3 and a name to the new column
top_3_from = f_df["Names"].value_counts().head(3).reset_index(name="count")
top_3_from.columns = ['person', 'count']

# Loop through your sent emails
for msg in t_messages:
	# Get the name of the person you're emailing	
	if(msg["to"][0]["name"] != ""):	
		to_messages.append(msg["to"][0]["name"].split()[0])
# Turn the array into a data frame		
t_df = pd.DataFrame(to_messages, columns=['Names'])
# Aggregate values, get the top 3 and a name to the new column
top_3_to = t_df["Names"].value_counts().head(3).reset_index(name="count")
top_3_to.columns = ['person', 'count']

# Using all the email subjects, generate a wordcloud
wordcloud = WordCloud(width=800, height=300).generate(text)
# Download the wordcloud image
wordcloud.to_file("mail_dashboard/wc_email.png")

# Create the dashboard layout
app_ui = ui.page_fluid(
    ui.tags.style(
        """
        .app-col {
            border: 1px solid black;
            border-radius: 5px;
            background-color: #eee;
            padding: 8px;
            margin-top: 5px;
            margin-bottom: 5px;
        }
        """
    ),
    ui.h2({"style": "text-align: center;"}, "Email Dashboard"),
    ui.row(
        ui.column(
            6,
            ui.div(
                {"class": "app-col"},
               ui.h2({"style": "text-align: center;"},"From: Emails"),
               ui.output_plot("_from_"),
            ),
        ),
        ui.column(
            6,
            ui.div(
                {"class": "app-col"},
                ui.h2({"style": "text-align: center;"},"To: Emails"),
                ui.output_plot("_to_"),
            ),
        ),
    ),
    ui.row(
        ui.column(
            12,
            ui.div(
                {"class": "app-col"},
                ui.h2({"style": "text-align: center;"},"Email Subject's Wordcloud"),
				ui.output_image("image"),
            ),
        )
    ),    	
)

def server(input, output, session):
# Display the "From" emails	
	@output
	@render.plot
	def _from_():
		g = sns.catplot(data=top_3_from,x="person",
                                                y="count",hue="person",kind="bar")
		return g
		
# Display the "To" emails
	@output
	@render.plot
	def _to_():
		h = sns.catplot(data=top_3_to,x="person",
                                                y="count",hue="person",kind="bar")
		return h		
		
# Display the Wordcloud	
	@output
	@render.image
	def image():
		from pathlib import Path
		dir = Path(__file__).resolve().parent
		img: ImgData = {"src": str(dir / "wc_email.png"), "width": "800px",       
                                                  "height":"300px"}
		return img

# Start the server
app = App(app_ui, server, debug=True)

To run it, we can simply go to the terminal and type:

$ shiny run --reload mail_dashboard/app.py

Our application will be running on port 5000 of localhost, so we just need to open our favorite browser and go to the following address:

http://localhost:8000

If you want to learn more about our Email APIs, please go to our documentation Email API Overview.

Don’t miss the action, join our LiveStream Coding with Nylas:

Related resources

How to create and read Google Webhooks using Ruby

Create and read your Google webhooks using Ruby and Sinatra, and publish them using Koyeb. Here’s the full guide.

Build mail merge and email templates using TinyMCE Rich Text Editor

Learn how to build Mail Merge and Email Template functionality in your email workflow using TinyMCE Rich Text Editor.

Send emails using TinyMCE Rich Text Editor

Learn how to improve your email workflow using TinyMCE Rich Text Editor.