Skip to content

Install the Backend (CLI + mail-sync)

The backend is the engine of all of MailAgent: it syncs email in the background, runs AI classification, and maintains the local database. The desktop App is just its graphical interface. Get the backend running first, then install the App.

The whole process is five steps and takes about 15 minutes if you follow along.

Step 1: Clone the repo and create a virtual environment

Section titled “Step 1: Clone the repo and create a virtual environment”

Open a terminal (Terminal or iTerm2) and run:

Terminal window
git clone https://github.com/ChenyqThu/MailAgent.git ~/Documents/MailAgent
cd ~/Documents/MailAgent
python3 -m venv venv
source venv/bin/activate
pip install -e ".[cli,dev]"
cp .env.example .env

The last line, pip install -e ".[cli,dev]", installs the mailagent command into the virtual environment. The -e (editable install) flag makes code changes you pull via git pull take effect immediately, with no reinstall needed.

Verify the install:

Terminal window
which mailagent # should point to venv/bin/mailagent
mailagent --version # expected output 3.0.0

Step 2: Set up the databases in Notion (critical and easy to miss)

Section titled “Step 2: Set up the databases in Notion (critical and easy to miss)”

MailAgent syncs email into two Notion databases: one for email, one for the calendar. You must create these two databases in Notion first and set up their fields per the tables below—the field names and types must match exactly, or sync will fail.

2a. Create the Integration and get the Token

Section titled “2a. Create the Integration and get the Token”
  1. Open www.notion.so/my-integrations in your browser.
  2. Click New integration, give it a name (e.g. MailAgent), and associate it with your workspace.
  3. After creating it, copy the Internal Integration Token (starts with ntn_)—this is the NOTION_TOKEN in .env.

Create a new Notion database (type /database on a page → Table - Full page) and add the fields per the table below. Field names must correspond exactly:

Field nameTypeDescription
SubjectTitleEmail subject (just rename the built-in title column of the database)
Message IDTextUnique email identifier, used for deduplication
Thread IDTextThread identifier, shared by emails on the same topic
FromEmailSender address
From NameTextSender display name
ToTextRecipient
CCTextCarbon copy
DateDateEmail date
Parent ItemRelation (pointing to this database itself)Thread-head relation, stringing one topic together
MailboxSelectInbox / Sent / Archive, etc.
Is ReadCheckboxWhether read
Is FlaggedCheckboxWhether flagged
Has AttachmentsCheckboxWhether it has attachments
AI ActionSelectAI-suggested action (Reply needed / For reference only / …)
AI PrioritySelectOptions: Critical / Urgent / Important / Normal / Low
AI Review StatusSelectOptions: Pending / Reviewed

Parent Item is a Relation that points to itself: when creating the field, choose this database itself as the data source. It lets replies on the same topic hang under the thread head.

Once it is set up, open the database’s top-right ⋯ → Connections → and add the MailAgent Integration you just created, otherwise it has no write permission. The 32-character hexadecimal segment in the database URL is the EMAIL_DATABASE_ID:

https://www.notion.so/<workspace>/<this segment is the DATABASE_ID>?v=...

2c. Create the calendar database (6 fields)

Section titled “2c. Create the calendar database (6 fields)”

Likewise create a new database and set up:

Field nameTypeDescription
TitleTitleEvent title
Event IDTextUnique event identifier, used for deduplication
TimeDate (with start/end)Event start and end time
URLURLTeams / meeting link
LocationTextLocation
OrganizerTextOrganizer

Remember to add the Integration connection here too; the ID in the URL is the CALENDAR_DATABASE_ID.

Step 3: Fill in the five required values in .env

Section titled “Step 3: Fill in the five required values in .env”

Open ~/Documents/MailAgent/.env in any editor and fill in at least these five values:

Terminal window
NOTION_TOKEN=ntn_xxxxxxxx # the Integration Token from step 2a
EMAIL_DATABASE_ID=xxxxxxxx # the ID of the email database from step 2b
CALENDAR_DATABASE_ID=xxxxxxxx # the ID of the calendar database from step 2c
USER_EMAIL=[email protected] # your email address
MAIL_ACCOUNT_NAME=Exchange # the name of this account in Mail.app (used by the AppleScript backend)

Not sure what your account is named in Mail.app? Run:

Terminal window
mailagent debug mail-structure

It will list all accounts and mailboxes in Mail.app; put your account name into MAIL_ACCOUNT_NAME.

The full set of optional configuration (Feishu, Redis, AI gateway, individual feature toggles) is documented with comments in .env.example; use what you need.

MailAgent switches between two mailbox-access paths with a single line of config:

Terminal window
MAILAGENT_BACKEND=applescript # code default; or change to davmail
BackendHow it connects to the mailboxWho it’s forSpeed
applescriptDrives the built-in macOS Mail.app directlyAlready have your mailbox set up in Mail.app and want the least hassle~1 second per email
davmailBridges corporate Exchange via DavMail (IMAP / SMTP / CalDAV)Corporate Exchange / Microsoft 365 users who want it faster and more stable~236 ms per email

Getting it working with AppleScript first is the simplest: as long as your mailbox is already signed in within Mail.app, no extra components are needed. Once you’re comfortable, consider switching to DavMail.

DavMail is a standalone Java bridge program that translates Exchange into standard email protocols. Beyond the line above, you also need to add:

Terminal window
MAILAGENT_BACKEND=davmail
DAVMAIL_USER=[email protected] # usually the same as USER_EMAIL
DAVMAIL_CIPHER_KEY=xxx # must match the cipher key in your local davmail.properties
# DAVMAIL_IMAP_PORT=1143 # must match davmail.properties
# DAVMAIL_SMTP_PORT=1025
# DAVMAIL_ROOT=/absolute/path/MailAgent/davmail-poc # absolute path required for the packaged App

The DavMail process is typically kept resident with PM2 under the name davmail-poc. DAVMAIL_CIPHER_KEY must match the cipher key in your local davmail.properties exactly, or the credentials cannot be decrypted.

Step 5: Grant macOS permissions and start the service

Section titled “Step 5: Grant macOS permissions and start the service”

The terminal App that runs MailAgent (Terminal / iTerm2) needs the permissions below. Open System Settings → Privacy & Security and grant each one:

PermissionLocationPurpose
Full Disk AccessPrivacy & Security → Full Disk AccessRead Mail.app’s local database (the SQLite radar)
Automation → MailPrivacy & Security → AutomationOperate Mail.app via AppleScript (mark read / flag / draft)
Automation → System EventsPrivacy & Security → AutomationSimulate keystrokes to paste content when creating drafts
AccessibilityPrivacy & Security → AccessibilitySystem Events sends keystrokes
Screen RecordingPrivacy & Security → Screen RecordingOnly needed when screenshotting a draft with --screenshot

If the system doesn’t pop up a permission request automatically, run mailagent debug mail-structure once to trigger it, then go to the locations above and check the boxes. Note: a process started by PM2 inherits the permissions of the terminal it was started in; switching terminals requires re-authorization.

For development / testing, run in the foreground:

Terminal window
python3 main.py

For production / long-running use, daemonize it in the background with PM2 (note that you must specify the Python interpreter inside the venv):

Terminal window
npm install -g pm2
pm2 start main.py --name mail-sync --interpreter ./venv/bin/python3
pm2 save && pm2 startup

Common PM2 commands:

Terminal window
pm2 status # check whether the process is online
pm2 logs mail-sync # tail the logs
pm2 restart mail-sync # restart
Terminal window
mailagent admin health -o json | jq .data.healthy # expect true
tail -f logs/sync.log # there should be no ERROR lines in the logs

When you see the SQLite radar running every 5 seconds and healthy is true, the backend is installed.

Once the backend is ready, the next step is to load your historical email into Notion: Initial Sync. If you also want the graphical interface after installing the backend, go to Install the Desktop App.


Learn more: README Quick Start · Full CLI Command Reference · DavMail and the Architecture Core