Mail background jobs – reading, commands, AI classification, e-mail task, sending
How the e-mail job types work, their time limits, states and tables, from reading to bulk sending.
Job types
| Type | Behaviour |
|---|---|
email (global, every minute, if the module's mail reading switch is not 0) | email/email::processForCronqueue(): e-mails of the active email_source entries (Gmail label), oldest first, within 50 s (cost estimate based on attachment count); e-mail and attachments (ZIP unpacked, PDF text extracted) via the shared Dlbtdocstore::addDocument() path according to the company's email storage rule; memory-saving base64 decoding, inline images filtered out. No filter or AI here. Tables: email_message, email_source, email_attachments, email_hash, email_pipeline_log, doc. |
email_commands (global, every minute) | processCommandsForCronqueue(): INGESTED e-mails; the system's task prefix in the subject → task proposal (PENDING_APPROVAL); the system's command block in the body → structured proposal (PENDING_APPROVAL); the system hashtag → FILTERED with a flag; otherwise FILTERED (goes on to AI). 50 s, max 100 e-mails. Tables: email_message, email_proposal, email_pipeline_log. |
email_ai (global, every 2 minutes) | processAiForCronqueue(): FILTERED e-mails; prompt from subject, sender, body and thread history; Tier-1 call (a small OpenAI model, Gemini as fallback; without a key an "ignore" answer); proposals into email_proposal; confidence above the threshold → PROCESSED, below PENDING_APPROVAL; AI error → AI_RETRY (3×), then ERROR. Prerequisite: an OpenAI or Gemini API key in the module settings. |
email_task (template rows scheduled by task frequency) | task/emailtask::processForCronqueue(): the payload's email_task_id or the company's due tasks; markRun() at once; the Dlbtemailtask engine within 40 s (folder-based API or IMAP query, the e-mail is not stored); remainder → continuation row; on error fail_count++, after 3 consecutive failures deactivation and notification; with notify=1 a notification on real processing. Tables: emailtask, notification, invoice, invoice_document, document, file, permission_scope. |
otpkelfo_ingest (global, 05:40, only with a configured Gmail query and account) | task/otpkelfo::processForCronqueue(): Gmail search excluding the processed label (max 25 messages), ZIP attachments into storage/tmp_otpkelfo/, a file row (status=0, as for a manual upload), the processed message labelled (label created if needed). |
mail_sweep (global, every 5 minutes) | mail/batch::processSweepForCronqueue(): starting from the log rows, starts e-mails that are due but were not queued or are stuck (sending). |
mail_batch (dispatch only) | mail/batch::processForCronqueue(): scheduled sending of recipients split into batches by sendBulk(), via the shared dlbtmail->send() path (block list, channel, size cap). |
mail_message (dispatch only) | processMessageForCronqueue(): payload only email_id; the content lives on the log row; thanks to the atomic claim in runQueued() a withdrawn e-mail is not sent. |