Start a project →

Live on this site · every contact-form message goes through it

Inbox Triage: the email manager behind our inbox

When you send us a message, it lands in a queue. Fixed rules label it, a fixed set of rules decides what may happen next, and a routine enquiry gets an acknowledgement while anything sensitive waits for a person. Each message gets one reply at most, and every step is logged.

How it is built

The AI suggests. The rules decide. A person stays in charge.

1

One queue, one record

Every message becomes one job in one store. The same sender, subject and text twice is one job, not two.

2

Claimed with a lease

A worker claims a job for a few minutes. If it stops halfway, the lease runs out and the job is picked up again, with a limit on attempts.

3

Labels, not decisions

The model is not configured on this install, so fixed rules produce the same three labels — category, urgency, and whether a person should read it. Either way nothing writes the reply.

4

Outbox before send

A reply is written to an outbox before it is sent, and the provider's answer is recorded. One reply per job, never two.

What happens to your message

Every step from contact form to reply

  1. The contact form checks the message and queues it. The team is emailed a copy at the same moment, so nothing depends on the queue alone.

  2. Every message becomes one job. A job in progress is claimed, so two workers cannot both handle it, and the queue stops taking work at 500 open jobs.

  3. Fixed rules drop bulk mail and anything from a no-reply, bounce or internal address, and flag urgent words and support problems.

  4. Bulk mail and robot mailboxes stop here. Our own domains and no-reply, bounce and notification addresses are refused before anything is sent.

  5. The model reads the message as data and returns a category, an urgency from 0 to 5 and a "needs a person" flag. If the call fails, the rules decide alone.

  6. The AI's labels can only make the outcome more careful. Complaints, support problems and urgent messages always wait for a person.

  7. A routine enquiry gets a short, fixed acknowledgement. The system does not write its own replies; only your first name is used.

  8. Everything that is not routine sits on a review board until someone approves a reply or closes it.

  9. The worker sends from the outbox. A failed send is retried after 1, 2, then 4 minutes and so on, and set aside for a person if it keeps failing.

  10. The result of every send is recorded. Finished messages are deleted after a set period; the details are in the privacy notice.

State model

One job, a few states, one record of truth

StatusMeaningCan move to
newQueued, not yet claimedprocessing
processingA worker holds the lease and is classifying itoutbox, awaiting review, ignored, dead letter
awaiting reviewNeeds a person before any replyoutbox, ignored
outboxA reply is staged, or retrying after a failed sendsent, dead letter
sentThe email provider accepted the replyclosed
ignoredBulk mail, a no-reply sender, or closed by a personclosed
dead letterKept failing, or the address was refuseda person decides

Guardrails

What it will never do

The pipeline

No database, no framework

Plain PHP and locked JSON files, a worker that runs every minute, and a review board behind a password. The same design works with Gmail, Outlook or a helpdesk as the intake.

Current status: replies are being written to a log file on our server rather than emailed — the delivery provider is not configured yet, so nothing has left the building. Enquiries are still stored and read by a person.

Contact form
  └─ validate + dedupe → job (new)
      └─ worker lease → processing
          ├─ rules: spam / no-reply / urgent / support
          ├─ Claude: category · urgency · needs_human
          ├─ policy gate → acknowledge | review | ignore
          ├─ outbox (one reply per job)
          ├─ send → sent | retry with backoff
          └─ dead letter → a person decides
Ask the agentOnline now