Use casesWorkflow
AI Legal Document Intake Agent
An AI agent that receives documents via email, parses attachments, confirms receipt, tracks what has been submitted, and requests missing items — automating the most tedious part of legal case onboarding.
The problem
Legal document intake is a slow, manual process. When a law firm opens a new case, the client needs to submit a stack of documents — engagement letters, identification, financial records, contracts, insurance policies. These documents arrive via email in batches, often over days or weeks, with inconsistent naming, mixed formats, and missing items.
Paralegals and legal assistants spend hours tracking what has been received, what is missing, and chasing clients for outstanding documents. Each reminder email is manually composed. Each attachment is manually downloaded, renamed, and filed. When a client sends three PDFs with names like "scan001.pdf", someone has to open each one to figure out what it is.
This is exactly the kind of structured, repetitive work that an AI agent can handle — but the agent needs to receive email with attachments, parse document content, and reply in the same conversation thread. Most email APIs do not support this full workflow.
How an AI agent solves this
A legal intake agent monitors a dedicated mailbox for incoming document submissions. When a client sends an email with attachments, the agent downloads each file, classifies the document type using an LLM or document parser, updates the case checklist, confirms receipt, and tells the client exactly what is still missing. It follows up automatically when deadlines approach.
- Receives documents via email attachments — PDFs, images, Word files
- Classifies each document against the case requirements checklist
- Confirms receipt with a clear list of what was received and what is outstanding
- Sends reminders for missing documents as deadlines approach
- Maintains a single threaded conversation per case for clear audit trails
How it works with Robotomail
Robotomail gives your intake agent a dedicated mailbox with full attachment support. Clients email documents directly to the agent. Attachments are stored in Cloudflare R2 and delivered to your webhook with download URLs. The agent processes them and replies in the same thread.
Step 1: Register a webhook for incoming documents. Set up a webhook to receive all inbound messages. Each delivery is signed with HMAC-SHA256 via the X-Robotomail-Signature header.
curl -X POST https://api.robotomail.com/v1/webhooks \
-H "Authorization: Bearer rm_live_..." \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"url": "https://your-firm.com/hooks/document-intake",
"events": [
"message.received"
]
}
JSONStep 2: Receive documents and attachments. When a client emails documents, Robotomail stores the attachments in R2 and delivers the message with download URLs to your webhook. Your agent downloads each file via the attachments API and classifies the document type.
{
"event": "message.received",
"timestamp": "2026-09-23T10:00:00Z",
"data": {
"message_id": "11111111-1111-4111-8111-111111111111",
"mailbox_id": "22222222-2222-4222-8222-222222222222",
"mailbox_address": "legal-intake@yourcompany.com",
"from": "client@lawfirm.com",
"to": [
"legal-intake@yourcompany.com"
],
"cc": [],
"subject": "Documents for Case #2026-0334",
"body_text": "Hi, please find the signed engagement letter and ID verification attached. I will send the financial statements tomorrow.",
"thread_id": "33333333-3333-4333-8333-333333333333",
"received_at": "2026-09-23T10:00:00Z",
"attachments": [
{
"id": "44444444-4444-4444-8444-000000000001",
"filename": "engagement-letter-signed.pdf",
"content_type": "application/pdf",
"size_bytes": 245000
},
{
"id": "44444444-4444-4444-8444-000000000002",
"filename": "id-verification.jpg",
"content_type": "image/jpeg",
"size_bytes": 1200000
}
]
}
}Step 3: Confirm receipt and list missing items. The agent replies in the same thread with a checklist showing what has been received and what is still outstanding. The client sees everything in one conversation.
# inReplyTo below stands for the fetched message.messageId; see the reply example below.
curl -X POST https://api.robotomail.com/v1/mailboxes/{mailbox_id}/messages \
-H "Authorization: Bearer rm_live_..." \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"to": [
"client@lawfirm.com"
],
"subject": "Re: Documents for Case #2026-0334",
"bodyHtml": "<p>Hi Maria,</p><p>I have received and logged the following documents for Case #2026-0334:</p><ul><li>Engagement letter (signed) — confirmed</li><li>ID verification — confirmed</li></ul><p>Still outstanding:</p><ul><li>Financial statements (last 3 years)</li><li>Property deed</li><li>Insurance declarations page</li></ul><p>Please send the remaining items at your convenience. Let me know if you have any questions.</p>",
"inReplyTo": "<original-message@example.com>",
"bodyText": "Hi Maria, I have received and logged the following documents for Case #2026-0334: Engagement letter (signed) — confirmed ID verification — confirmed Still outstanding: Financial statements (last 3 years) Property deed Insurance declarations page Please send the remaining items at your convenience. Let me know if you have any questions."
}
JSONStep 4: Send deadline reminders. When documents remain outstanding as a deadline approaches, the agent sends a follow-up in the same thread — no manual tracking required.
# inReplyTo below stands for the fetched message.messageId; see the reply example below.
curl -X POST https://api.robotomail.com/v1/mailboxes/{mailbox_id}/messages \
-H "Authorization: Bearer rm_live_..." \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"to": [
"client@lawfirm.com"
],
"subject": "Re: Documents for Case #2026-0334",
"bodyHtml": "<p>Hi Maria,</p><p>Just a friendly reminder — we are still waiting on 3 documents for Case #2026-0334:</p><ul><li>Financial statements (last 3 years)</li><li>Property deed</li><li>Insurance declarations page</li></ul><p>We need these by March 28 to stay on schedule. Can you send them this week?</p>",
"inReplyTo": "<original-message@example.com>",
"bodyText": "Hi Maria, Just a friendly reminder — we are still waiting on 3 documents for Case #2026-0334: Financial statements (last 3 years) Property deed Insurance declarations page We need these by March 28 to stay on schedule. Can you send them this week?"
}
JSONUse a custom domain like intake@smithlaw.com for a professional appearance. Robotomail auto-configures DKIM, SPF, and DMARC, and attachments are stored securely in R2 with access controlled through your API key.
Key benefits
- Instant acknowledgment: Clients get confirmation within seconds of submitting documents — no waiting to hear back
- Automated tracking: The agent maintains a live checklist of received and missing documents per case
- Secure attachment storage: Documents are stored in Cloudflare R2 and accessible only through authenticated API calls
- Clear audit trail: Every interaction is threaded and stored — useful for compliance and case management
- Faster case onboarding: Reduce intake time from weeks to days — read the API docs and launch post to get started
Get started and set up your first intake mailbox. Full attachment support on every plan, with a 30-day money-back guarantee.
Connect the workflow to a real reply
The webhook's data.message_id is a database ID used to retrieve or deduplicate a message. Fetch it with the GET message endpoint, then use the response's message.messageId (the RFC Message-ID) as inReplyTo. Keep data.thread_id for your application's conversation state. Do not use a database ID or thread ID as a reply header. Stop and investigate if the fetched message has no Message-ID.
Examples use illustrative IDs. Replace them with IDs from your account; never construct an email Message-ID from a database ID. Exchange mail only between your agent and your verified email address. Upgrade to email anyone. See plans for higher limits.
Verify the webhook signature over the raw body, persist the event and deduplicate on the database message ID before acknowledging it. Run your application logic from a durable queue. The database, calendar, CRM and model functions shown above belong to your application.
This shell example fetches an incoming email and builds all required send fields. Set ROBOTOMAIL_API_KEY, ROBOTOMAIL_MAILBOX_ID and ROBOTOMAIL_MESSAGE_ID in your environment. Apply your recipient and approval rules before sending.
# Requires jq. Use mailbox_id and message_id from the verified webhook.
original=$(curl --fail --silent --show-error \
"https://api.robotomail.com/v1/mailboxes/$ROBOTOMAIL_MAILBOX_ID/messages/$ROBOTOMAIL_MESSAGE_ID" \
-H "Authorization: Bearer $ROBOTOMAIL_API_KEY") || exit 1
payload=$(printf '%s' "$original" | jq -e --arg body "Thanks, I received your message." '
.message | if (.messageId | type == "string" and length > 0) then
{to: [.fromAddress], subject: ("Re: " + .subject), bodyText: $body, inReplyTo: .messageId}
else error("Original email has no Message-ID") end
') || exit 1
curl --fail --silent --show-error \
"https://api.robotomail.com/v1/mailboxes/$ROBOTOMAIL_MAILBOX_ID/messages" \
-H "Authorization: Bearer $ROBOTOMAIL_API_KEY" \
-H "Content-Type: application/json" \
--data-binary "$payload"
Read receive and reply and webhook verification for the full setup.