# Mail intake bot - ops handover Version: none shown by the bot (code as of commit 2e13216) · Written 2026-10-23 · Escalation: RPA dev team, Teams channel **#rpa-support** ## 1. What the bot does Every 10 minutes Windows Task Scheduler starts the bot. It reads the **unread** emails in the referrals mailbox, saves every attachment, checks that it is a PDF of 20 MB or less, and copies it to the **shared intake folder**. Each attachment becomes one item in the bot's queue with a status and a note. Input: emails with PDF attachments. Output: PDF files in the shared intake folder, plus one line per item in the log file `logs/intake.log`. It drives no desktop apps or websites. It only talks to the mailbox and the shared folder. ## 2. How it works ``` Windows Task Scheduler (every 10 min) └─ starts → intake bot (no window) ──reads──> referrals mailbox (unread mail only) │ ├─ saves attachments → bot's temp folder (dev only) ├─ copies PDFs → shared intake folder (ops can open) ├─ records items → queue database (dev only) └─ writes → logs/intake.log (ops can open) ``` - **Task Scheduler** starts the bot. The bot has no screen, so you never see it running. - **Referrals mailbox:** the bot reads unread mail only. **Reading a mail marks it as read**, so the bot never sees it again. - **Temp folder:** every attachment is saved here first. Quarantined files stay here. Ops cannot open it. - **Shared intake folder:** good PDFs end up here. This is the bot's output. - **Queue database:** one row per attachment (sender, subject, status, note). Only dev can open it. - **logs/intake.log:** one line per item processed, plus errors. This is ops' main window into the bot. **One run, step by step:** 1. Check that no item from an earlier run is still "Processing". If one is, **stop the whole run** (see E02). 2. Sign in to the mailbox: 3 tries, 30 seconds apart. 3. For every unread mail: save each attachment and add it to the queue as **New**. The mail is now marked read. 4. For each New item, oldest first: mark it **Processing**, check it, copy it to the shared folder, then set its final status and note. 5. Write one log line per item: `item -> ()`. ## 3. Before a run The bot runs by itself, so "before a run" means "keep these true all the time": - [ ] The settings file is in the bot folder. It holds the mailbox address, user and password and the shared-folder path. If the mailbox password expires or changes, dev must update this file (E01). - [ ] The bot folder has its `logs` folder, plus the `data` folder holding the queue database and a `tmp` folder. The bot does not create these itself. If one is missing, the run crashes before it writes anything (E10). - [ ] The bot machine can reach the shared intake folder (E05). - [ ] **Only one machine runs the bot.** Two copies would read the same mailbox and split or duplicate the work. - Rules for senders of referrals (tell the referral sources): - Send **PDF only, 20 MB or less**. Good: `referral.pdf` at 3 MB. Bad: `referral.docx`, a phone photo `.jpg`, or a 35 MB scan (all go to Quarantined, E03). - **No password-protected PDFs** (E04). - Give each attachment its **own file name**. Bad: two mails that both attach `scan.pdf` - the second one overwrites the first (E08). - Logos and images in email signatures count as attachments too. They show up as Quarantined. That is noise, not a lost referral. ## 4. During a run - **Do not end the bot's task in Task Scheduler and do not restart the machine while a run is going.** If the bot stops halfway through an item, that item stays "Processing" and **every later run stops at once** until dev clears it (E02). - To stop the bot, ask dev to **disable** the scheduled task. Disabling stops future runs without cutting a run in half. - Do not open, move or rename files in the shared intake folder while they are being copied. - A run normally takes seconds, or about 1.5 minutes when the mailbox is slow to answer. The bot has **no watchdog**: if the mailbox or the shared folder stops responding, the run can hang with no time limit (E09). ## 5. Where to look when something goes wrong Ops can open `logs/intake.log` and the shared intake folder. The queue database is dev only. | Question | Where to look | |---|---| | Did the run finish? | `logs/intake.log`. The bot writes **no** "run started" or "run finished" line. A run with no new mail writes nothing at all, so a silent log does not tell you whether the bot is healthy (Fix #10). | | Which items failed? | `logs/intake.log` → search for `-> Failed`, `-> Quarantined` and `encrypted` | | Why did one item fail? | The same log line. The reason is in brackets at the end, e.g. `item 312 -> Quarantined (not a PDF or over 20 MB)` | | Is the bot blocked? | `logs/intake.log` → `Previous item still Processing - aborting` repeated every 10 minutes (E02) | | Can it reach the mailbox? | `logs/intake.log` → `IMAP connect failed (1/3)`, `(2/3)`, `(3/3)` (E01) | | Did the bot already retry? | Only mailbox sign-in is retried (the `(n/3)` lines). **Items are never retried.** | | Did the PDF reach the shared folder? | The shared intake folder. Look for the attachment's file name. The log shows the item number only, not the file name (Fix #11). | | Who sent the item? | Not visible to ops. Sender and subject are only in the queue database. Ask dev with the item number. | | Which version is running? | The bot shows no version. Ask dev for the commit it runs (section 10). | ## 6. Statuses The bot has no screen, so statuses have no colour. You see them in `logs/intake.log` as `-> ()`. | Status | Note written | Meaning | What ops does | |---|---|---|---| | New | (empty) | Saved from the mailbox, waiting for processing. You see it only if a run stopped early. | Nothing. The next run picks it up. | | Processing | (unchanged) | The bot is working on it right now. **If it is still Processing after the run, it blocks every later run.** | Nothing during a run. If it stays, see E02. | | Done | ` pages saved` | PDF checked and copied to the shared intake folder | Nothing | | Done | `encrypted - not readable` | **Needs follow-up.** Password-protected PDF. It was **not** copied to the shared folder, even though the status says Done. | E04 | | Quarantined | `not a PDF or over 20 MB` | **Needs follow-up** (unless it is a signature image). Not copied to the shared folder. | E03 | | Failed | `share unreachable: ` | **Needs follow-up.** The copy to the shared folder failed. **The bot never retries it.** | E05 | ## 7. Exception catalogue | ID | What you see | How the bot identifies it | Where it is recorded | Type | Who acts | What to do | Escalate when | |---|---|---|---|---|---|---|---| | E01 | New referrals are not reaching the shared folder. The log shows `IMAP connect failed (1/3)` up to `(3/3)` at every 10-minute run. | It tries to sign in to the mailbox 3 times, 30 seconds apart. After the 3rd failure the run ends. | Log: one warning line per try with the mailbox's error text. **The final "gave up" is not logged** (Fix #3). Nothing is queued, and unread mail stays unread (not lost). | System | Bot, then Ops / Dev | Read the error text. Words like "authentication", "login failed" or "password" mean the mailbox password expired or changed: go to dev. Network words like "getaddrinfo failed" or "timed out" mean the machine has no network: check the bot machine's network and wait for the next run. | Password-type error at any time, or network errors on 3 runs in a row (30 min). Send: times of the first and last `(3/3)` lines and the error text (never the password). | | E02 | The log shows `Previous item still Processing - aborting` every 10 minutes, and no new referrals arrive. | At the start of every run the bot checks whether any item is still Processing. If one is, it stops at once, before it opens the mailbox. | Log: one error line per run. The blocking item is in the queue database only. | System | **Dev** | Ops cannot clear this (database only). New mail is safe: it stays unread in the mailbox and is picked up once dev clears the blocked item. | Always, at the **first** occurrence. Send: time of the first abort line, and the last `item ->` line before it. The blocking item is usually the next number. | | E03 | Log: `-> Quarantined (not a PDF or over 20 MB)` | The file name does not end in `.pdf`, or the file is bigger than 20 MB | Log line. The file stays in the bot's temp folder and is not copied to the shared folder. | Business | Ops | If it was a signature image or logo, do nothing. If it was a real referral, ask the sender to resend it as a PDF of 20 MB or less. Ops cannot find out the sender alone, so ask dev with the item number. | You need the original file or the sender's details: send the item number and log time. | | E04 | Log: `-> Done (encrypted - not readable)`. The referral is missing from the shared folder although the status says Done. | The PDF is password-protected | Log line. The file is **not** copied to the shared folder. | Business | Ops | Ask the sender for an unprotected copy. Get the sender's details from dev with the item number. | You need the original file: send the item number and log time. | | E05 | Log: `-> Failed (share unreachable: ...)` | Copying to the shared intake folder gives an error (folder offline, no permission, disk full) | Log line, with the error text in brackets | System | Ops, then Dev | Check that the shared folder opens from the bot machine and has free space. Check whether a half-copied file with that name is in the shared folder; if so, tell dev. **The bot will not retry this item.** | Always: only dev can put the item back in the queue. Send: item number(s), log time, the error text. | | E06 | The run stops with no log line for an item, then E02 starts at the next run. | A damaged PDF, or a file that disappeared from the temp folder, makes the bot crash mid-item | **Nothing in the log** for the crash (Fix #3, #4). The item stays Processing. | System | Dev | Same as E02 | Always. Send: the time E02 started. | | E07 | A sender says they sent a referral, but nothing appears in the log or the shared folder. | Mail with no attachment, or an attachment without a file name, is skipped | **Nowhere.** The mail is marked read and no item is created (Fix #8). | Business | Ops | Check the referrals mailbox for that mail. If it has no attachment, ask the sender to resend with the PDF attached. If it does have a PDF, go to dev. | The mail has a PDF attachment but no item. Send: the mail's received time (not its content). | | E08 | Two items both show `Done`, but the shared folder has only one file, or the file has the wrong content. | No check. Two attachments with the same file name overwrite each other. | Log: two Done lines. Only one file survives. | System | Dev | Ask dev to recover the overwritten referral from the mailbox. Remind senders to use unique file names. | Always. Send: both item numbers and log times. | | E09 | Referrals stop arriving with no error in the log, and no `Previous item still Processing` lines either. | No check. The mailbox or the shared folder stopped responding mid-run, and the bot waits with no time limit. | Nothing (Fix #9, #10) | System | Dev | Ops cannot tell this apart from "no new mail" in the log. If senders confirm mail was sent more than 30 minutes ago and nothing arrived, escalate. | 30 minutes with known mail and no log lines. Send: the time of the last log line. | | E10 | No log lines at all from any run, even when mail is waiting. | The settings file, the `data` or `tmp` folder, the queue database or the `logs` folder is missing, or the temp folder is full | Nothing (the crash happens before or outside logging) | System | Dev | Check that `logs/intake.log` still exists in the bot folder, then escalate. Mail read during a crash in step 3 may be marked read but never queued (lost from the bot's view). | Always. Send: the time of the last log line, and any change to the machine since then (moves, cleanups, password changes). | ## 8. What the bot recovers by itself | Problem | What the bot does | Limit | After the limit | |---|---|---|---| | Mailbox sign-in fails | Waits 30 s and tries again | 3 tries (about 1.5 minutes) | Run ends with nothing logged. The next scheduled run 10 minutes later tries again (E01). | | Items left New (run stopped before processing them) | Picked up by the next run | Every 10 minutes | - | | Anything else | **Nothing.** Failed, Quarantined and encrypted items are never retried. A Processing item left by a crash blocks all runs until dev clears it. | - | E02, E05 | How long to wait before acting: **one or two scheduled runs (10-20 minutes)** for mailbox errors. **Do not wait** for E02: escalate at the first abort line. ## 9. Known incidents Newest first. The three "fix" changes in the history are notes in the code only. **The behaviour did not change**, so all three can still happen. | When / version | What ops saw | Cause | What to do now | Ops could handle? | |---|---|---|---|---| | Logged as fixed 2026-10-23 | The mailbox password expired and every run failed silently | Mailbox password expiry. The per-try warnings were in the log, but the final failure was not. | Watch for `IMAP connect failed (3/3)` with a password-type error and escalate (E01). The final failure is still not logged. | Partly | | Logged as fixed 2026-10-23 | Password-protected PDFs reached the shared folder empty | Encrypted PDFs | Today they are marked `Done (encrypted - not readable)` and **not** copied. Follow E04. | Partly | | Logged as fixed 2026-10-23 (seen in the log 2026-09-04) | The bot was blocked for a whole day after a crash left one item in Processing. Ops reset it by hand. | A crash mid-item leaves it Processing, and every run then stops | Still happens. Ops no longer has database access, so escalate at the first `Previous item still Processing` line (E02). | Partly | ## 10. Releases and version check - How an update arrives: dev replaces the bot's code on the bot machine. There is no launcher or auto-update. - How to confirm it applied: the bot shows no version anywhere. Ask dev to confirm the commit running on the machine (Fix #13). - If the version did not change: report it in #rpa-support. Only one machine may run the bot (section 3), so there is never a second copy to keep in step. ## 11. Escalating to dev Post in the Teams channel **#rpa-support**. Send: the exception ID from section 7 (e.g. "E02"), the item number(s), the time of the log line(s), and the matching lines copied from `logs/intake.log`. Never send: passwords, the settings file, sender addresses, email subjects, or attachment contents. ## 12. Failure-class check - F1 covered in section 3 (settings file, folders, database, share access) and E10. - F2 not applicable: the bot drives no desktop windows. It works with a mailbox and a file share only. - F3 covered in E09 (no time limit on the mailbox or the share) and Fix #9. No screens to wait for. - F4 covered in section 3 sender rules, E03 (signature images), E07 (no attachment) and E08 (same file name). - F5 covered in E07 and E10 (mail marked read, nothing recorded) and Fix #8. - F6 covered in E05 (a half-copied file may be in the share after Failed). - F7 covered in section 6 and E04 (encrypted shown as Done) and Fix #5. - F8 covered in E02 (every run aborts with no limit), E09 (hang, no watchdog) and section 8. There is no auto-rerun loop. - F9 covered in section 4 (never end the task mid-run; disable it instead). - F10 covered in E02 and E06. - F11 covered in section 5 and Fix #3, #10, #11, #12 (crashes not logged, sender and file name only in the database). - F12 covered in section 10 and Fix #13 (no version shown). ## 13. Fix before handover (dev team) | # | Gap | Why it hurts ops | Where (file:line) | |---|---|---|---| | 1 | The three "fix" commits (9e47ec2, 9f400df, 2e13216) only add comments. No behaviour changed. | Ops and dev believe these incidents are closed | `intake.py:89-91` | | 2 | A stale Processing row blocks every run, the blocking id is not logged, and releasing it needs a database edit | Ops has no database access, so every crash becomes a dev call plus lost hours | `intake.py:74-76` | | 3 | Uncaught errors are never written to the log: "Mailbox unreachable", PDF read errors, file errors. They go only to the console, which nobody sees. | Ops cannot see why a run died | `intake.py:37`, `intake.py:71-88` | | 4 | A damaged PDF crashes the run (the PDF read is outside any error handling), leaving the item Processing | One bad attachment stops all intake (E06 → E02) | `intake.py:61` | | 5 | An encrypted PDF is stored as `Done` and not copied | Reads as success but needs follow-up (F7) | `intake.py:62-63` | | 6 | Failed items are never retried, because only New items are picked | A short share outage needs a dev database edit | `intake.py:78` | | 7 | Attachment file names are used as-is: the same name overwrites the earlier file in temp and in the share, and names are not sanitised (path characters) | Silent loss of a referral; security risk | `intake.py:50`, `intake.py:65` | | 8 | Fetching marks mail read before it is committed (one commit after all mails). Mails with no attachment leave no record. | A crash during fetch loses mail from the bot's view; "missing referral" questions cannot be answered | `intake.py:44-54` | | 9 | No timeout on the mailbox connection or the share copy, and no watchdog | A run can hang without any sign | `intake.py:31`, `intake.py:65` | | 10 | No "run started / finished / N new mails" log line | A silent log means either "healthy, no mail" or "dead": ops cannot tell | `intake.py:71-84` | | 11 | The item log line has no file name, sender or subject reference, and the README's `queue_viewer.xlsx` is not in the repo and reads the database | Ops cannot match a log line to a mail or a file in the share | `intake.py:84`, `README.md:6` | | 12 | The code does not create `data/`, `data/tmp/`, `logs/` or the `queue` table | A fresh or cleaned machine crashes silently (E10) | `intake.py:17-18`, `intake.py:23`, `intake.py:73` | | 13 | No version string anywhere | Ops cannot confirm an update applied | repo-wide | | 14 | `logs/intake.log` holds a sender email address, in a line format the current code does not write | Personal data in a file ops reads and may paste into tickets; suggests an older build ran at some point | `logs/intake.log:6` | | 15 | Quarantined files stay in the temp folder, out of ops' reach, and signature images create Quarantined noise | Ops cannot inspect or forward a quarantined file | `intake.py:46-60` |