inbox-jev

Every ten minutes it labels your new mail with Jev, archives what has nothing for you to do and unsubscribes you from pitches it can verify.

The inbox, after one pass
← →mail.google.com/mail/u/0/#inbox≡
Ana DiazJev/ImportantJev/Needs ReplySigned contract by Friday? — Hi, can you confirm the signature date so…9:04 AM
Acme BankJev/ActionApprove payment to Acme Supplies — A payment of $2,400.00 is waiting for your…8:51 AM
Brand StudioJev/ReviewJev/NewslettersAnnouncing our spring collection — New shapes, same hands…8:12 AM
Bea OrtizJev/ActionInvitation: Weekly sync @ Wed 10am — bea@partner.example has invited you7:40 AM
Google CloudJev/ActionJev/Needs ReplyVerify your domain before Oct 20 — Action required: your verification…Oct 14
Leo MarchettiJev/ImportantRe: offer for the senior role — Thanks for the call yesterday. I'd like to…Oct 14
HubSpot FormsJev/ActionNew submission: Request a demo — Company: Norte Logística · Size: 40…Oct 14
StripeJev/ActionYour card ending in 4242 expires soon — Update it to avoid a failed…Oct 13
Marta RuizJev/ImportantJev/Needs ReplyCan we move Thursday? — Something came up on my side…Oct 13

Only mail that needs you stays in the inbox

Each email gets one of eight labels. Personal mail, and automated mail that asks you to do something, stay in the inbox. Receipts, notifications, newsletters, promotions and sales pitches are archived. When Jev isn't sure enough, the email stays where it is with Jev/Review and its best guess.

LabelsArchiveNeeds reply
See the categories
The pass itself
>_[ RUN LOG ]≡
$ inbox-jev run -a you@example.com --mode act
09:10:03 run started account=you@example.com mode=act lookback=2d
09:10:05 message processed category=marketing confidence=0.94 action=archive_unsubscribe previous_contact=never archive_group=false timings_ms={gmail:212,rule:3,sent:0,jev:1480,apply:160}
09:10:05 unsubscribe list=promo.shop.example method=one_click status=ok
09:10:07 message processed category=action_required confidence=0.93 action=keep needs_reply=0.85
09:10:09 message processed category=notification confidence=0.55 action=archive archive_group=true
09:10:10 message processed category=important decided_by=rule flags_only=true
09:10:12 message processed category=newsletter confidence=0.50 action=keep low_confidence=true
09:10:13 message processed category=transactional confidence=0.99 action=archive
09:10:14 message processed category=spam confidence=0.95 action=spam reply_without_thread=true
09:10:16 message processed category=cold_outreach confidence=0.96 action=archive_unsubscribe known_contact_kept=true
09:10:17 message processed category=notification confidence=0.91 action=archive
09:10:19 message processed category=action_required confidence=0.90 action=keep needs_reply=0.20
09:10:20 run finished processed=14 archived=9 unsubscribed=1 review=1 errors=0
09:10:20 next run in 10 min (launchd)

A pass runs every ten minutes on your own machine

A launchd or systemd timer starts it. Each email gets a category, a confidence and an action, and the decision goes into a SQLite database so you can look it up later or undo it.

CLIPython 3.11+SQLite
Follow one email through
Statistics
Price free Categories 8 Triage pass every 10 min Digest daily 08:00 Archive bar 0.80 Unsubscribe bar 0.90 Worked examples 50 Decision records 53 Modes dry_run · label · act Licence MIT

Playground

Try it on an email(live)

Paste an email, or take a sample, and the published package decides it here the way a pass would: the headers' signals, what Jev gets, Jev's answer and the policy's verdict, for an inbox with no rules and the default categories. What you paste goes to a function on this site and on to TypeSafe under the author's key, and is not stored.

>_[ PLAYGROUND ]≡

Nothing decided yet. Take a sample or paste an email, then ask Jev.

How it decides

How it decides(8)

Every email goes through the same steps. The eight in the figure are worked examples from the spec, and each one is also a test that runs the real code. Pick one and follow it to what Gmail shows afterwards.

>_[ THE PER-EMAIL PIPELINE ]≡
Eight emails from the spec · pick one Stays in the inbox Leaves the inbox Gmail's spam folder Decided by a rule: Jev is not asked no rule category + confidence action Your rules the allowlist andthe sender ruleslearned from yourcorrections.A match decidesthe categoryon the spot. Jev gets the headers,the first lines,the domains linkspoint to, Gmail'sauth verdicts, andwhether you everwrote to them.Answers onecategory andhow sure it is. Policy At or above thecategory's bar(0.80, 0.90):its action.Archive categoriesthat togetherreach 0.90:archived.Anything else:stays, Jev/Review. Signed contract by Friday? ana@client.example · a client with a rule Approve payment to Acme Supplies alerts@bank.example · automated Re: quick question about your pipeline sam@growthagency.example · a stranger Your weekly product analytics digest@analytics.example · a tool you use RE: Updated permit schedule for review noreply@dailywire-news.example · a fake reply This week in product news@weekly.example · a learned rule Re: quick question about your pipeline sam@growthagency.example · a known contact Announcing our spring collection hello@brand.example · Jev is not sure Jev/Important stays Jev/Action stays Jev/Review stays, flagged Jev/Transactional archived Jev/Notifications archived Jev/Newsletters archived Jev/Marketing archived, unsubscribed Jev/Outreach archived, unsubscribed Jev/Spam moved to Spam Eight emails from the spec · tap one Stays in the inbox Leaves the inbox Gmail's spam folder Decided by a rule: Jev is not asked Your rules the allowlist and thesender rules learnedfrom your corrections Jev sees headers, firstlines, link domains,auth verdicts andwhether you wroteto them. Answers acategory and howsure it is. Policy Above the category'sbar (0.80 / 0.90):its action. Archivecategories togetherat 0.90: archived.Else stays, withJev/Review. Signed contract by Friday? ana@client.example · a client with a rule Approve payment to Acme Supplies alerts@bank.example · automated Re: quick question about your pipeline sam@growthagency.example · a stranger Your weekly product analytics digest@analytics.example · a tool you use RE: Updated permit schedule for review noreply@dailywire-news.example · a fake reply This week in product news@weekly.example · a learned rule Re: quick question about your pipeline sam@growthagency.example · a known contact Announcing our spring collection hello@brand.example · Jev is not sure Jev/Important stays Jev/Action stays Jev/Review stays, flagged Jev/Transactional archived Jev/Notifications archived Jev/Newsletters archived Jev/Marketing archived, unsubscribed Jev/Outreach archived, unsubscribed Jev/Spam moved to Spam

Re: quick question about your pipeline · sam@growthagency.example

Archived with Jev/Outreach, unsubscribed with one click

Jev says cold outreach at 0.96, above the 0.90 bar. The sender passes DMARC in Gmail's own headers, the email has a List-Unsubscribe header, the sender isn't a group or anyone you have written to, and the account is in act mode, so one POST with List-Unsubscribe=One-Click (RFC 8058) ends the sequence.

Spec example EX-04. A test with the same id runs the real code.

The spec's per-email pipeline, with its two flowcharts drawn as one. Allowlisted senders and senders with a rule never reach Jev. The unsubscribe gate sits on the two bottom archive rows and is spelled out under "What it does".
Your rules first

Your rules decide first

An allowlisted sender, or a sender with a rule, is decided without asking Jev. Rules come from your corrections, from rules set, or appear on their own after Jev has answered the same category three times at 0.95 or more.

Then Jev

Jev reads the headers and the first lines

It also gets the domains the links point to, Gmail's own SPF, DKIM and DMARC verdicts, and whether you have ever written to the sender. It never gets a full URL, and the body is never stored. It answers with one category and how sure it is.

Then policy

The confidence picks the action

If it reaches the category's bar, that category's action runs. If several archive categories add up to 0.90, the email is archived under the strongest of them. Anything else stays in the inbox with Jev/Review.

What it does

What it does to your inbox(6)

← →mail.google.com/mail/u/0/#inbox≡
Jev/Action5
Jev/Important4
Jev/Needs Reply3
Jev/Review1
Jev/Invoices2
Jev/Transactional
Jev/Notifications
Jev/Newsletters
09:10:05 message processed category=transactional confidence=0.97 action=archive
09:10:07 message processed category=notification confidence=0.55 action=archive archive_group=true
09:10:08 message processed category=newsletter confidence=0.88 action=archive
09:10:09 message processed category=marketing confidence=0.94 action=archive_unsubscribe
09:10:11 message processed category=cold_outreach confidence=0.71 action=keep low_confidence=true
09:10:12 message processed category=spam confidence=0.95 action=spam
09:10:14 message processed category=transactional confidence=0.99 action=archive
09:10:15 message processed category=notification confidence=0.91 action=archive
09:10:17 message processed category=marketing confidence=0.73 action=archive archive_group=true
09:10:18 message processed category=newsletter confidence=0.96 action=archive
09:10:19 run finished processed=14 archived=9 unsubscribed=1 review=1 errors=0
cold_outreach at 0.96, bar is 0.90
dmarc=pass in Gmail's Authentication-Results
List-Unsubscribe + List-Unsubscribe-Post present
not a Google Group, not a discussion list
you never wrote to sam@growthagency.example
mode act, 3 of 10 unsubscribes left this run
POST https://unsub.sequencer.example/u/abc List-Unsubscribe=One-Click → 200
Weekly ProductJev/NewslettersJev/ImportantThis week in product — Label changed by youOct 8
Weekly ProductJev/ImportantThis week in product — Decided by your rule, a week laterOct 15
Brand StudioJev/NewslettersAnnouncing our spring collection — Jev/Review removed by you: suggestion acceptedOct 9
Brand StudioJev/NewslettersAutumn lookbook — Archived by your ruleOct 14
Sam LeeJev/OutreachRe: quick question — Rule from three Jev answers at 0.96Oct 12
Daily DealsJev/MarketingJev/NewslettersWeekend picks — Label changed by youOct 10
Daily DealsJev/NewslettersWeekday picks — Decided by your ruleOct 13
Sam LeeJev/OutreachFollowing up — Archived by your rule, Jev not askedOct 15
Acme BankJev/ActionJev/Needs ReplyApprove payment to Acme Supplies — Keep rule: Jev still asked whether it needs youOct 15
jevinbox-jevAPP8:00 AM

3 emails need you

you@example.com · last 24h · mode: act

Needs reply (2)

What Jev did · last 24h

Jev/Notifications31
Jev/Marketing9
Jev/Newsletters7
Jev/Transactional6
To review1
Processed64
$ inbox-jev run --mode dry_run --limit 30
dry run: records decisions, touches nothing
processed=30 would_archive=19 would_unsubscribe=3 review=2

$ inbox-jev run --mode label
labels only: nothing leaves the inbox

$ inbox-jev restore -a you@example.com --since 1d
restored 12 emails to the inbox
  newsletter 7 · marketing 4 · notification 1
labels removed: Jev/Newsletters, Jev/Marketing, Jev/Notifications
restored emails are never processed again
Categories

Categories(8)

These are the defaults the package ships with, and they are one person's preferences. You can change the criteria, the bars and the actions, or add a category, in your own copy of categories.yaml.

KeepJev/ImportantNo bar
Actionstays in the inbox

Written by a real person specifically to you: clients, teammates, partners, investors, candidates, decisions and questions addressed to you. It is not mass mail that only greets you by name. Allowlisted senders and emails you pull back to the inbox land here.

KeepJev/ActionNo bar
Actionstays in the inbox

Automated email that needs you to do something: approve a payment, update an expiring card, verify a domain, sign a document, fix something before a deadline. Also a lead from your own website's form, a meeting someone booked with you, and a calendar invitation waiting on your answer.

ArchiveJev/TransactionalBar 0.80
Actionarchived

The record of something you did or bought, with nothing left to do: receipts, paid invoices, order and booking confirmations, shipping updates, verification codes, copies of documents you already signed.

ArchiveJev/NotificationsBar 0.80
Actionarchived

FYI alerts and digests from the tools you use: GitHub, Slack, Calendar, Drive, Jira, Linear, analytics, monitoring, CI. Reminders of meetings already in your calendar and plain "Accepted" replies to invitations you sent. There is nothing for you to do with them.

ArchiveJev/NewslettersBar 0.80
Actionarchived, never unsubscribed

Editorial content you subscribed to: newsletters, digests, blog updates, industry news. It informs rather than sells.

Archive + unsubJev/MarketingBar 0.90
Actionarchived and unsubscribed

Promotional email from a legitimate company: ads, sales, discounts, launches, webinars, event promotions, upsells. Unsubscribed only when the sender passes DMARC and offers a List-Unsubscribe header.

Archive + unsubJev/OutreachBar 0.90
Actionarchived and unsubscribed, never from a known contact

An unsolicited pitch from someone you have no relationship with, written to look personal: agencies, lead-gen, recruiting, "quick question" sequences, podcast and sponsorship invitations.

SpamJev/SpamBar 0.90
Actionmoved to Gmail's Spam

Scams and phishing: a reply that answers no thread, links to domains unrelated to the sender, a conversation between other people pasted into a message to you, an authentication pass that proves a domain other than the one it claims. Below 0.90 it stays in the inbox with Jev/Review, already labeled, for you to confirm.

Questions

Before you let it touch your mail(6)

What does it never do?

It never deletes an email. It unsubscribes only when the sender passes DMARC and the email has a List-Unsubscribe header, and even then only when the sender is not a group or a discussion list, you have never written to them, Jev is at 0.90 or more and the account is in act mode. Starred mail, mail you moved back and mail whose labels you edited by hand are left alone. Below a category's bar it does nothing that would need undoing.

What does it send to Jev?

The headers that matter, the first characters of the body, the domains the links point to without the rest of the URL, Gmail's SPF, DKIM and DMARC verdicts, and whether you have ever written to the sender. The database and the log keep the sender, the subject and the classification, and never the body. The search of your sent mail reads only the To, Cc and Bcc fields.

How do I start without risk?

Run it in dry_run for a week. Every decision is recorded and the digest tells you what it would have done, but nothing in Gmail changes and no rule is learned. Switch to label when the categories look right, and to act when the labels do, for every category at once or one at a time with act_categories.

What if it gets one wrong?

Fix it in Gmail. Swap the label, remove Jev/Review or move the email back to the inbox, and the next pass records the correction and a rule for that sender. Tomorrow's digest lists what it learned. To undo a whole day, inbox-jev restore --since 1d moves everything archived or spammed back and removes its labels. An unsubscribe can't be undone, which is why it has the longest list of conditions.

Where does it run?

On your Mac or Linux machine, as a launchd or systemd user timer that inbox-jev schedule install sets up, with a pass every ten minutes and the digest at 08:00. It can also run on a server with Docker and systemd timers, with a watchdog for stale runs, nightly backups and Slack alerts. Run one copy per account.

Why trust the rules?

Every rule is written down twice. The functional spec has 50 worked examples, and each one is a test that runs the real code. The 53 architecture decision records say why each rule is the way it is and which alternatives were rejected. A change to how it decides is checked against real mail before it is merged.

Install

Install it in two commands

It is free, MIT licensed, and runs on your own machine. You need a TypeSafe API key and a Google OAuth client of your own, and the setup wizard walks you through both. Slack is optional. Your email goes to Google and to TypeSafe, and to no other server.

Python 3.11 or newer, uv or pipx

The first command installs the tool. The second asks for your TypeSafe key, walks you through a Google OAuth client of your own, authorizes your Gmail and offers a first dry run. Then inbox-jev schedule install runs it every ten minutes.

uv tool install inbox-jev && inbox-jev init

If you run it from a checkout of the repo, it uses the checkout. Run it on a server with Docker

>_[ inbox-jev init ]≡
$ inbox-jev init
[1/5] TypeSafe API key      checked, saved to .env
[2/5] Google OAuth client   found in ~/Downloads, copied
[3/5] Slack bot token       skipped
[4/5] Gmail account         you@example.com authorized
[5/5] Schedule              every 10 min + daily 08:00

first dry run? [Y/n] y
processed=30 would_archive=19 would_unsubscribe=3 review=2