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

TypeBehaviour
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.