# Mail intake bot - ops handover Version: none (the bot has no version number, see section 10) · Written 2026-10-23 · Escalation: RPA dev team, Teams channel **#rpa-support** ## 1. What the bot does Every 10 minutes the bot checks the referrals mailbox for **unread** mail. It saves every attachment, checks that it is a PDF under 20 MB that is not password-protected, and copies it to the **shared intake folder**. It records one queue entry per attachment, with a status and a short note, and writes one line per attachment to its log. It has no screen of its own. It does not drive any desktop app. It only talks to the mailbox and the shared folder. ## 2. How it works ``` Windows Task Scheduler (every 10 min) └─ starts → Mail intake bot (no window) ├─ reads ──> Referrals mailbox (unread mail only) ├─ saves → bot's temp folder (data/tmp) ├─ copies → Shared intake folder <- the output ops can open ├─ writes → queue database (data/queue.db) <- ops cannot open └─ writes → logs/intake.log <- ops can open ``` - **Task Scheduler** starts the bot every 10 minutes. There is nothing to click. - **Referrals mailbox:** the bot only picks up mail that is still unread. Fetching a mail marks it as read. - **Temp folder:** every attachment is saved here first, and it stays here even when it is rejected. - **Shared intake folder:** good PDFs are copied here under their original file name. - **Queue database:** one entry per attachment, with its status and note. Only the dev team can open it. - **logs/intake.log:** one line per attachment, plus warnings and errors. This is ops' main window into the bot. **One run, step by step:** 1. Check that no attachment is left half-done from an earlier run (status Processing). If one is, the run stops at once (E03). 2. Log in to the mailbox. If that fails it tries 3 times, 30 seconds apart (E01, E02). 3. Take every unread mail and save all its attachments, including signature logos and images, as new queue entries. 4. For each new entry, check it, copy it to the shared intake folder, and write the result to the queue and the log. ## 3. Before a run - [ ] The settings file sits next to the bot. It holds the mailbox server, user and password, and the shared folder path. If anything is missing the bot stops without writing anything to the log (E07). - [ ] The bot's `data` folder exists and holds the queue database and a `tmp` subfolder, and the `logs` folder exists. The bot does not create these itself (E07). - [ ] The shared intake folder can be reached from the bot machine (E06). - [ ] The mailbox password has not expired. Know its expiry date and tell the dev team before it expires (E02). - [ ] Tell senders the input rules: - Send referrals as **PDF**, with a file name ending in `.pdf`, under **20 MB** and **not password-protected**. - Good: `referral_2026-10-23_REF123.pdf`, 3 MB, opens without a password. - Bad: `referral.docx`, a scan of 25 MB, or a PDF that asks for a password. - **Use a unique file name per referral.** Two attachments with the same name overwrite each other in the shared folder (E08). - Good: `referral__.pdf`. - Bad: every sender attaching `referral.pdf`. ## 4. During a run - **Do not open or read new mail in the referrals mailbox** (Outlook, webmail, phone). The bot only picks up **unread** mail. A mail someone has read is never picked up. - If a mail was read by mistake, mark it **unread** again. The next run picks it up. - **To stop the bot:** disable the scheduled task in Task Scheduler and let the current run finish. **Never end a run while it is running.** That leaves an attachment in Processing and blocks every later run (E03). - **A run looks stuck when:** - the log shows "Previous item still Processing - aborting" every 10 minutes (E03), or - referrals are known to have been sent, yet neither the log nor the shared folder has changed for over 30 minutes (E07). - **The bot has no watchdog and no time limit.** It never gives up or unblocks by itself. Escalate as soon as you see either sign. ## 5. Where to look when something goes wrong | Question | Where to look | |---|---| | Did the run finish? | There is no "run started" or "run finished" line. A run with no new mail writes nothing. Look at the time of the newest line in `logs/intake.log`. | | Is the bot blocked? | `logs/intake.log`: the line "Previous item still Processing - aborting" repeating every 10 minutes (E03). | | Can it reach the mailbox? | `logs/intake.log`: lines "IMAP connect failed (1/3)", "(2/3)", "(3/3)" (E01, E02). | | Which attachments failed? | `logs/intake.log`: lines `item -> Failed`, `-> Quarantined` or `-> Done (encrypted - not readable)`. | | Why did one attachment fail? | The text in brackets at the end of that same log line. | | Did the file arrive? | The shared intake folder: look for the file name. | | Did the bot already retry? | Mailbox login is retried 3 times per run (the "(n/3)" lines). Attachments are **never** retried. | | Which version is running? | There is no version number (section 10). | The log line shows only the item number, not the sender or the file name. To turn an item number into a sender or file, ask the dev team (#rpa-support). ## 6. Statuses The bot has no screen, so no status has a colour. Ops see the final statuses as plain text in the log line `item -> ()`. | Status (note) | Colour | Meaning | What ops does | |---|---|---|---| | New ("") | none, not in the log | Saved from the mailbox and waiting to be checked and copied. | Nothing. It is handled later in the same run, or in the next run if the mailbox login works. | | Processing ("") | none, not in the log | Being checked or copied right now. If it is still there on the next run, the bot crashed on it and **every later run is blocked**. | If the log shows "Previous item still Processing - aborting", follow E03. | | Done (" pages saved") | none (log text) | The PDF was copied to the shared intake folder. | Nothing. | | **Done ("encrypted - not readable")** | none (log text) | **Needs follow-up.** The PDF is password-protected. It was **NOT copied** to the shared folder, even though the status says Done. | Follow E05: ask the sender for a copy without a password. | | Failed ("share unreachable: ...") | none (log text) | The copy to the shared intake folder failed. **The bot never retries it.** | Follow E06. | | Quarantined ("not a PDF or over 20 MB") | none (log text) | Rejected. The name does not end in `.pdf`, or the file is over 20 MB. Signature logos and images in mail land here too. | Follow E04. | ## 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 | One or two lines "IMAP connect failed (1/3)" or "(2/3)", then normal item lines again | The mailbox login or connection fails; the bot waits 30 s and tries again | `logs/intake.log` (warning line with the error text) | System | Bot | Nothing. It recovered within the same run. | It happens on several runs in a row, which means E02 | | E02 | "IMAP connect failed" lines on every run, and no new item lines or new files | 3 connection tries, 30 s apart, all fail; the run then ends. The final failure is **not** written to the log. | `logs/intake.log` (warning lines only) | System | Dev | Read the error text. "getaddrinfo failed" means a network or name problem on the bot machine; check that its network is up. A login or authentication error usually means the mailbox password expired or changed. | Always, if it lasts more than 30 minutes. Send the time of the first failing line and the error text. **Never send the password in chat.** | | E03 | "Previous item still Processing - aborting" every 10 minutes. No new files in the shared folder. | At start the bot finds an attachment left in Processing from an earlier run (a crash, a damaged PDF, or a run ended by hand), so it stops. **It never clears this by itself**, and the line does not say which item. | `logs/intake.log` (error line) | System | Dev | Do not end or restart anything. Mail is not lost while blocked: it stays unread and is picked up after the fix. | Always, at once. Send the time of the first "still Processing" line and the last `item ->` line before it. The dev team checks whether the file reached the shared folder, then resets the item in the database. | | E04 | `item -> Quarantined (not a PDF or over 20 MB)` | The file name does not end in `.pdf`, or the file is over 20 MB. The note does not say which. | `logs/intake.log`; the file stays in the bot's temp folder | Business | Ops | Usually a signature logo or image: ignore it. If a real referral is missing from the shared folder, ask the sender to resend it as a PDF under 20 MB. | A real `.pdf` under 20 MB is quarantined | | E05 | `item -> Done (encrypted - not readable)` | The PDF is password-protected (or restricted), so it is not copied | `logs/intake.log`; the file is **not** in the shared folder | Business | Ops | Ask the sender for the referral without a password. The new mail is picked up by itself. Check the log for this note at least daily, because the status says Done. | The sender's file opens without a password, yet it is still rejected. Send the item number and time. | | E06 | `item -> Failed (share unreachable: ...)` | Copying to the shared intake folder fails | `logs/intake.log` | System | Ops, then Dev | Check that the shared intake folder opens from the bot machine. Even when it works again, **the bot does not retry this attachment.** | Always. Once the share works, send the item numbers and times of the Failed lines; the dev team re-queues them. | | E07 | Referrals were sent, but nothing new appears in the log or the shared folder for over 30 minutes, and there are no warning lines | The bot crashed before writing to the log (settings file or folder missing, a damaged mail, or a hung mailbox connection: there is no time limit). It does not detect this. | Nowhere ops can see. Only Task Scheduler's run result shows it. | System | Dev | Make sure nobody has read the mails in the mailbox (section 4). If they did, mark them unread. | When the mails are still unread and nothing happens. Send the time the referral was sent, the time of the newest log line, and the subject line. Do not send patient details in chat. | | E08 | A referral is missing or the wrong one sits in the shared folder; two senders used the same file name | Not detected. Same-name files overwrite each other, both in the temp folder and in the shared folder. | Two `item -> Done` lines; only one file in the shared folder | Business | Ops, then Dev | Ask the senders to resend with unique file names. | You cannot tell which referral was lost. Send both item numbers and times. | ## 8. What the bot recovers by itself | Problem | What the bot does | Limit | After the limit | |---|---|---|---| | Mailbox connection or login fails | Tries again after 30 s | 3 tries per run (about 1.5 minutes) | The run ends. The next run, 10 minutes later, tries again. This repeats forever with no alert (E02). | | Attachments saved but not yet processed (New) | Carried over to the next run | None | They are processed only after a mailbox login succeeds | | Attachment left in Processing | **Nothing.** Every run stops. | None, it never clears | Dev resets it (E03) | | Copy to the shared folder fails | **Nothing.** The attachment is marked Failed. | No retry | Dev re-queues it (E06) | | Run hangs on the mailbox or the shared folder | **Nothing.** There is no time limit. | None | Dev (E07) | ## 9. Known incidents No dates or versions were recorded for the fixes below. The log does show one recorded lockout: on 2026-09-04 a mailbox network failure at 08:10 was followed by "still Processing" aborts at 08:20 and 08:30. | When / version | What ops saw | Cause | What to do now | Ops could handle? | |---|---|---|---|---| | Before handover, no version | Mailbox password expired and every run failed with nothing in the log | Login errors were not logged | The connection errors are now logged as warnings, but the final failure still is not. Follow E02. | Yes, with E02 | | Before handover, no version | Password-protected PDFs arrived in the shared folder empty | Encrypted PDFs were copied without a check | They are no longer copied, but they show as Done. Follow E05. | Partly: ops can chase the senders, but only by watching the note | | Before handover, no version (also seen 2026-09-04) | No new referrals for a whole day. The queue was blocked by one item stuck in Processing, and ops reset it by hand. | A crash during one attachment left it in Processing. Every later run stops. | The bot now logs "still Processing - aborting", but still never clears it. Escalate at once (E03). | Partly: ops can spot it, but only dev can clear it | ## 10. Releases and version check - **How an update arrives:** there is no updater. The dev team copies the new `intake.py` onto the bot machine. - **How to confirm it applied:** you can't. The bot shows no version anywhere (Fix item 10). Ask the dev team to confirm in #rpa-support. - **If the version did not change:** ask the dev team to copy the files again. - Only one machine runs this bot, and it rewrites nothing shared at start, so an old build cannot undo a newer one. ## 11. Escalating to dev Post in Teams **#rpa-support**. Send: - the exception ID from section 7, - the time of the first bad log line, - the item number(s) from the `item ->` lines, - the related lines copied from `logs/intake.log`. Never send: the mailbox password, the settings file, referral PDFs, or patient or sender details in chat. ## 12. Failure-class check - F1 covered in section 3 (settings file, folders, share, password expiry) and E07; Fix items 3 and 11. - F2 not applicable: the bot drives no windows; it talks to the mailbox and the shared folder directly. The closest risk, a person reading mail in the mailbox, is a rule in section 4. - F3 covered in E01, E02, E06 and E07; no time limit on the mailbox connection is Fix item 4. - F4 covered in section 3 input rules (PDF name, size, unique file names), E04 and E08; Fix items 7 and 9. - F5 covered in E05 (Done although nothing was copied); Fix item 1. - F6 covered in E03 (dev checks whether the file reached the shared folder before resetting) and section 4 (read mail is never picked up); mail marked read before being saved is Fix item 6. - F7 covered in section 6 ("encrypted" Done needs follow-up) and E05; Fix item 1. - F8 covered in section 8 (mailbox retries repeat forever) and E03 (the abort repeats every 10 minutes forever). - F9 covered in section 4: disable the scheduled task, never end a running run. - F10 covered in E03; Fix item 2. - F11 covered in section 5 (log only, item number only); Fix items 3, 8 and 9. - F12 covered in section 10; no version number is Fix item 10. ## 13. Fix before handover (dev team) | # | Gap | Why it hurts ops | Where (file:line) | |---|---|---|---| | 1 | Password-protected PDFs are marked Done but never copied. Restricted PDFs that open without a password are rejected too (`is_encrypted`). | Ops filtering on Failed or Quarantined never see them, and referrals go missing. Use Quarantined or Failed. | `intake.py:62-63` | | 2 | Any error inside `process()` (damaged PDF, missing temp file, a killed run) leaves the item in Processing. The start check aborts every run forever, never names the item, and never resets it. | A whole day without referrals; only dev can clear it (DB) | `intake.py:59-61`, `intake.py:74-76`, `intake.py:79-83` | | 3 | The final "Mailbox unreachable" error and every crash (missing `.env` key, missing table or folder, `TypeError` on an empty payload) go to stderr only, which Task Scheduler drops. Login errors are retried the same way as network errors (account lockout risk). | Ops see nothing, or only warnings | `intake.py:31-37`, `intake.py:51`, `intake.py:87-88` | | 4 | No timeout on the IMAP connection or the share copy | A hung run blocks all later scheduled runs silently | `intake.py:31`, `intake.py:65` | | 5 | Failed items are never retried; re-queueing needs a DB edit | Every share outage needs dev | `intake.py:66-67`, `intake.py:78` | | 6 | Fetching with RFC822 marks mail as read before the rows are committed. A crash in `fetch_new` loses that mail for good. | Referrals silently lost | `intake.py:44-54` | | 7 | Attachment file names are used as-is: same names overwrite each other in `data/tmp` and on the share, and an unsanitised name can write outside `data/tmp` (path traversal) | Wrong or missing referral; security risk | `intake.py:50`, `intake.py:65` | | 8 | The log line has the item number only: no sender, subject, file name, or run start/end line. `queue_viewer.xlsx` is named in the README but is not in the repo, and it reads the DB, which ops cannot open. | Ops cannot tie a failure to a referral without dev | `intake.py:84`, `README.md:6` | | 9 | The Quarantined note doesn't say which check failed (extension or size); only the extension is checked, not the content; rejected files stay in `data/tmp`, which ops cannot reach and which is never cleaned | Ops cannot tell senders what to fix | `intake.py:59-60` | | 10 | No version string anywhere, and no update mechanism | Ops cannot confirm an update applied | `intake.py:1-2` | | 11 | `data/`, `data/tmp/`, `logs/` and the `queue` table are never created by the code. The share path falls back to a hardcoded default. | A fresh install crashes silently | `intake.py:17-19`, `intake.py:23`, `intake.py:73` | | 12 | `.env` (mailbox credentials) is committed to git in the initial import | Credential exposure: rotate the mailbox password and remove the file from history | `.env`, commit `bc90067` | | 13 | `logs/intake.log` contains a line format the current code never writes, and it includes a sender email address | Personal data in the log | `logs/intake.log:6` | | 14 | A `BOT_WAS_RUN` marker file is written on every run and never read | Unclear purpose; confirm or remove | `intake.py:72` |