How to manage your contacts using NiceGUI

8 min read

Managing our contacts is an important task, as we want to have them updated as often as possible. And what could be better than building our interface to do that? We’re going to make a NiceGUI Contact Manager to update our contacts.

To build our Contact Manager, we will use NiceGUI, a Python-based Web-UI Framework.

Is your system ready?

Continue with the blog if you already have the Nylas Python SDK installed and your Python environment configured.

Otherwise, I recommend reading the post How to Send Emails with the Nylas Python SDK, where the basic setup is clearly explained.

What are we going to talk about?

  • What our NiceGUI Contact Manager will look like
  • Installing the required packages
  • Coding our NiceGUI Contact Manager
  • Running our NiceGUI Contact Manager

What our application will look like

When we run our Contact Manager, we’re going to display five contacts belonging to a group that we have defined. Of course, we’re free to display all contacts without worrying if they belong to a group. It’s our choice:

NiceGUI contacts manager

We need to select a contact and then click Update:

Select a contact to be updated

Let’s take a closer look:

Updating the contact

We’re going to change Hulk’s job title from Owner to Gym Owner and then click on Submit:

The contact was updated

When the contact gets updated, a lovely notification message will be displayed.

Installing the required packages

Besides the Nylas and Dotenv packages, we need to install the NiceGUI package:

$ pip3 install nicegui

That’s it. Nothing too complex or complicated.

Coding our NiceGUI Contact Manager

And it’s coding time. We will create a folder called NiceGUI, with a folder called assets. Then, we’re going to create a file called

Let’s start with the initialization section:

# Import your dependencies
from dotenv import load_dotenv
import os
from nylas import APIClient  # type: ignore
from nicegui import app, ui

# Add the assets folder as a local folder
app.add_static_files('/assets', 'assets')

# Load your env variables

# Initialize an instance of the Nylas SDK using the client credentials
nylas = APIClient(

# Dictionary to hold all contacts information
contact_info = {'id':'','given_name':'', 'surname':'', 'company_name':'',
                       'job_title':'', 'email':'', 'email_type':'', 'country':'', 'street_address':'',
                       'phone_number':'', 'phone_type':'', 'city':'', 'state':'', 'postal_code':'', 

# List to hold all contacts
contact_list = []

Let’s move into the fetch and update sections:

# Function to update a contact using our dictionary
def update_contact():
    contact = nylas.contacts.get(contact_info['id'])
    contact.given_name = contact_info['given_name']
    contact.surname = contact_info['surname']
    contact.company_name = contact_info['company_name']
    contact.job_title = contact_info['job_title']
    contact.emails[contact_info['email_type']] = [contact_info['email']]
    contact.phone_numbers[contact_info['phone_type']]  = [contact_info['phone_number']]
    if contact_info['street_address'] is not None or contact_info['street_address'] != '':
        contact.physical_addresses['Work'] = [{
                'format': 'structured',
                'city': contact_info['city'],
                'country': contact_info['country'],
                'state': contact_info['state'],
                'postal_code': contact_info['postal_code'],
                'type': contact_info['address_type'],
                'street_address': contact_info['street_address']}]
        # We try to save the contact
        ui.notify('The contact was updated!')
    except Exception as e:
        # If the update fails, display the error message

# Update the dictionary with the updated values
def update_field(field, value):
    contact_info[f'{field}'] = value

# For each selected contact, bring the details
def fill_contact_details(contact_id):
    # Call the contacts endpoint
    contact = nylas.contacts.get(contact_id)
    contact_info['id'] =	
    picture = contact.get_picture()
    file_name = f'{}.png'
    profile_image = open(f'assets/{file_name}', 'wb')
        contact_info['phone_number'] = list(contact.phone_numbers.values())[0][0]
        contact_info['phone_type'] = list(contact.phone_numbers)[0]
    except Exception as e:
        contact_info['phone_number'] = '123'
        contact_info['phone_type'] = 'Mobile'
    contact_info['given_name'] = contact.given_name
    contact_info['surname'] = contact.surname
    contact_info['company_name'] = contact.company_name
    contact_info['job_title'] = contact.job_title
        contact_info['address_type'] = list(contact.physical_addresses.values())[0][0]["type"]
    except Exception as e:
        contact_info['address_type'] = ""
        contact_info['email'] = list(contact.emails.values())[0][0]
        contact_info['email_type'] = list(contact.emails.keys())[0]
    except Exception as e:
        contact_info['email'] = ''
        contact_info['email_type'] = ''
        contact_info['country'] = list(contact.physical_addresses.values())[0][0]["country"]
    except Exception as e:
        contact_info['country'] = ''
        contact_info['street_address'] = list(contact.physical_addresses.values())[0][0]["street_address"]
    except Exception as e:
        contact_info['street_address'] = ''
        contact_info['city'] = list(contact.physical_addresses.values())[0][0]["city"]
    except Exception as e:
        contact_info['city'] = ''
        contact_info['state'] = list(contact.physical_addresses.values())[0][0]["state"]
    except Exception as e:
        contact_info['state'] = ''
        contact_info['postal_code'] = list(contact.physical_addresses.values())[0][0]["postal_code"]
    except Exception as e:
        contact_info['postal_code'] = ''
# 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:
    contact_list.append({'id': ,'full_name' : contact.given_name + " " + contact.surname})

Finally, the UI building part:

# Build the UI
with ui.row():
    with ui.column():
        # Define the table as an AG Grid
        grid = ui.aggrid({
            'columnDefs': [
                {'headerName': 'Id', 'field': 'id', 'hide': True},
                {'headerName': 'Contact Name', 'field': 'full_name', 'checkboxSelection': True},
            'rowSelection': 'simple',
        }).classes('h-45 w-80')

        # When we select a contact and press "Update"
        async def output_selected_row():
            row = await grid.get_selected_row()
            if row:

        # The update button
        ui.button('Update', on_click=output_selected_row)
    # Form to display the updatable fields
    with ui.column():
        profile_pic = ui.image()
        first_name = ui.input(label='First Name', placeholder='First Name', on_change = lambda e: update_field('given_name', e.value))
        last_name = ui.input(label='Last Name', placeholder='Surname', on_change = lambda e: update_field('surname', e.value))
        company_name = ui.input(label='Company Name', placeholder='Company Name', on_change = lambda e: update_field('company_name', e.value))
        job_title = ui.input(label='Job Title', placeholder='Job Title', on_change = lambda e: update_field('job_title', e.value))
        email = ui.input(label='Email', placeholder='Email', on_change = lambda e: update_field('email', e.value))
        phone_number = ui.input(label='Phone Number', placeholder='Phone Number', on_change = lambda e: update_field('phone_number', e.value))        
        country = ui.input(label='Country', placeholder='Country', on_change = lambda e: update_field('country', e.value))
        address = ui.input(label='Address', placeholder='Address', on_change = lambda e: update_field('street_address', e.value))
        city = ui.input(label='City', placeholder='City', on_change = lambda e: update_field('city', e.value))
        state = ui.input(label='State', placeholder='State', on_change = lambda e: update_field('state', e.value))
        postal_code = ui.input(label='Postal Code', placeholder='Postal Code', on_change = lambda e: update_field('postal_code', e.value))
        # Submit button
        ui.button('Submit', on_click=update_contact)

# Run our application = 'NiceGUI Contacts')

Running our NiceGUI Contact Manager

In order to run our application, we just need to type the following on the terminal window:

$ python
Running our NiceGUI Contact Manager

Our application will be running on port 8080 of localhost and of, and we don’t even need to open our favourite browser, as it will be open automagically.

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

You can sign up Nylas for free and start building!

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.