postulo-imap: read the job-hunt mailbox over IMAP and suggest timeline events; no POP3 #34

Closed
opened 2026-09-05 14:04:17 +00:00 by tiagoagueda · 0 comments
Owner

Observation

mailbox ingestion plugin "postulo-imap" (don't want to use pop3 for now)

Why

Every application produces mail: an acknowledgement, a rejection, an interview invitation with a date, an assessment link, eventually an offer. Today each has to be typed into the timeline by hand, which is why timelines go stale. docs/PLAN.md deferred email ingestion past v1; this is the plugin that does it, against the interfaces the milestone is building.

IMAP, not POP3, by decision. POP3 has no folders, no flags and no server-side state: it downloads, and usually deletes. IMAP lets Postulo read one folder the person chose, mark what it has processed, and leave everything else untouched — which is the only acceptable way to put a job tracker near a mailbox.

Shape

  • A separate package, postulo-imap, registering a sync in the postulo.syncs group and using a connection (#11): host, port (993, implicit TLS; STARTTLS as an option), username, password or app password (secret), the folder to read, and how to mark messages as processed (an IMAP keyword such as $Postulo, or moving them to a subfolder). IMAP4rev1 and rev2 (RFC 3501, RFC 9051) through imapclient (BSD-3) over the standard library's imaplib.
  • The person chooses what Postulo may read, by folder. Default: a folder named Jobs that they create and file into — never the inbox. A filter on their mail server can route recruiter mail there automatically; Postulo does not need to know how. Whole-mailbox reading is possible but is a deliberate second step with its own warning.
  • Polling through the scheduler #4 settles on, every few minutes; IMAP IDLE later, if anyone needs minutes to become seconds.
  • Matching a message to an application: the sender's domain against Company.website's domain, the sender against Contact.email, the company name or role title in the subject or body, and In-Reply-To threads of messages already matched. Unmatched mail is shown as such, and can be attached by hand.
  • Classifying it: rule lists per language — English, French and Portuguese from the start — for acknowledged, rejected, interview invitation (with the dates it proposes, offered to #14), assessment, offer received. Rules, not a model: they are inspectable, translatable and wrong in ways a person can see.
  • Nothing is written on a guess. Every match lands as a suggested event in a review queue, the same principle as captures ("captures always land in a review screen; nothing is saved on a guess"). Accepting records the event through record_event or change_status; declining teaches nothing yet, but is remembered so the same message is not suggested twice.
  • What is stored: message id, date, sender, subject, a short excerpt and the suggested kind. Not the body, by default. An option attaches the message as an uploaded document of a correspondence kind (#28) when the person wants the paper trail.
  • Authentication: app passwords first. Gmail requires one when two-factor is on, and Microsoft has been retiring basic authentication for years, so XOAUTH2 is the likely second step — heavier, and its own issue when it comes.

Classification

Enhancement. A separate package; changes nothing unless installed and connected. Not breaking.

Depends on

  • #11 — connection, secrets, and the postulo.syncs group
  • #4 — the scheduler that runs the polling
  • #14 (interview dates) and #28 (a correspondence kind): useful, not blocking

Open questions

  1. Should the plugin ever move or flag mail, or only read? Marking processed is a write to the mailbox. Proposal: a keyword flag by default (invisible in most clients), moving as an option, and a read-only mode that keeps its own record of seen message ids.
  2. JMAP (RFC 8620) for the servers that speak it — Fastmail, Stalwart, Cyrus? Same plugin, second protocol, some day.
  3. Which languages' rule lists ship first? en, fr, pt-PT, matching the project; contributors add theirs as data files, not code.
## Observation > mailbox ingestion plugin "postulo-imap" (don't want to use pop3 for now) ## Why Every application produces mail: an acknowledgement, a rejection, an interview invitation with a date, an assessment link, eventually an offer. Today each has to be typed into the timeline by hand, which is why timelines go stale. `docs/PLAN.md` deferred email ingestion past v1; this is the plugin that does it, against the interfaces the milestone is building. **IMAP, not POP3**, by decision. POP3 has no folders, no flags and no server-side state: it downloads, and usually deletes. IMAP lets Postulo read one folder the person chose, mark what it has processed, and leave everything else untouched — which is the only acceptable way to put a job tracker near a mailbox. ## Shape - **A separate package, `postulo-imap`**, registering a **sync** in the `postulo.syncs` group and using a **connection** (#11): host, port (993, implicit TLS; STARTTLS as an option), username, password or app password (secret), **the folder to read**, and how to mark messages as processed (an IMAP keyword such as `$Postulo`, or moving them to a subfolder). IMAP4rev1 and rev2 (RFC 3501, RFC 9051) through `imapclient` (BSD-3) over the standard library's `imaplib`. - **The person chooses what Postulo may read, by folder.** Default: a folder named *Jobs* that they create and file into — never the inbox. A filter on their mail server can route recruiter mail there automatically; Postulo does not need to know how. Whole-mailbox reading is possible but is a deliberate second step with its own warning. - **Polling** through the scheduler #4 settles on, every few minutes; IMAP `IDLE` later, if anyone needs minutes to become seconds. - **Matching a message to an application**: the sender's domain against `Company.website`'s domain, the sender against `Contact.email`, the company name or role title in the subject or body, and `In-Reply-To` threads of messages already matched. Unmatched mail is shown as such, and can be attached by hand. - **Classifying it**: rule lists per language — English, French and Portuguese from the start — for *acknowledged*, *rejected*, *interview invitation* (with the dates it proposes, offered to #14), *assessment*, *offer received*. Rules, not a model: they are inspectable, translatable and wrong in ways a person can see. - **Nothing is written on a guess.** Every match lands as a **suggested event** in a review queue, the same principle as captures ("captures always land in a review screen; nothing is saved on a guess"). Accepting records the event through `record_event` or `change_status`; declining teaches nothing yet, but is remembered so the same message is not suggested twice. - **What is stored**: message id, date, sender, subject, a short excerpt and the suggested kind. **Not the body**, by default. An option attaches the message as an uploaded document of a *correspondence* kind (#28) when the person wants the paper trail. - **Authentication**: app passwords first. Gmail requires one when two-factor is on, and Microsoft has been retiring basic authentication for years, so **XOAUTH2** is the likely second step — heavier, and its own issue when it comes. ## Classification Enhancement. A separate package; changes nothing unless installed and connected. Not breaking. ## Depends on - #11 — connection, secrets, and the `postulo.syncs` group - #4 — the scheduler that runs the polling - #14 (interview dates) and #28 (a correspondence kind): useful, not blocking ## Open questions 1. Should the plugin ever *move* or *flag* mail, or only read? Marking processed is a write to the mailbox. Proposal: a keyword flag by default (invisible in most clients), moving as an option, and a read-only mode that keeps its own record of seen message ids. 2. JMAP (RFC 8620) for the servers that speak it — Fastmail, Stalwart, Cyrus? Same plugin, second protocol, some day. 3. Which languages' rule lists ship first? en, fr, pt-PT, matching the project; contributors add theirs as data files, not code.
tiagoagueda added this to the 0.2.0 milestone 2026-09-05 14:04:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
Postulo/postulo#34
No description provided.