MOLTED EMAIL

Inbound Email

Receive and classify inbound email with intent detection, routing actions, and safety flags.

Molted Email can receive inbound email on your mailboxes, classify intent, and route messages to the right handler.

List inbound messages

GET https://api.molted.email/v1/inbound
curl
curl "https://api.molted.email/v1/inbound?tenantId=tenant_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

Response
[
  {
    "id": "msg_abc123",
    "tenantId": "tenant_abc123",
    "fromEmail": "customer@example.com",
    "toEmail": "support@yourdomain.com",
    "subject": "Need help with billing",
    "bodyText": "I have a question about my invoice...",
    "classification": {
      "intent": "billing",
      "confidence": 0.92,
      "suggestedAction": "notify_owner"
    },
    "createdAt": "2026-03-01T12:00:00Z"
  }
]

Approve routing

For messages that require manual approval before being routed:

POST https://api.molted.email/v1/inbound/:id/approve
curl
curl -X POST https://api.molted.email/v1/inbound/msg_abc123/approve \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "tenant_abc123",
    "action": "notify_owner"
  }'

Classify intent

Classify the intent of an inbound email to determine how your agent should respond.

CLI
molted classify --subject "Re: Invoice" --body "Where is my invoice?"
curl
curl -X POST "https://api.molted.email/v1/agent/classify-intent" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "tenant_abc123",
    "subject": "Re: Invoice",
    "bodyText": "Where is my invoice?"
  }'

Classify response

Response
{
  "intent": "billing",
  "confidence": 0.92,
  "suggestedAction": "notify_owner",
  "classifierVersion": "v3-safety",
  "flags": [],
  "allScores": [
    { "intent": "billing", "score": 0.92, "keywordMatches": 3, "subjectMatches": 1, "bodyMatches": 2 },
    { "intent": "support", "score": 0.15, "keywordMatches": 1, "subjectMatches": 0, "bodyMatches": 1 },
    { "intent": "interested", "score": 0, "keywordMatches": 0, "subjectMatches": 0, "bodyMatches": 0 },
    { "intent": "not_now", "score": 0, "keywordMatches": 0, "subjectMatches": 0, "bodyMatches": 0 },
    { "intent": "objection", "score": 0, "keywordMatches": 0, "subjectMatches": 0, "bodyMatches": 0 },
    { "intent": "legal", "score": 0, "keywordMatches": 0, "subjectMatches": 0, "bodyMatches": 0 },
    { "intent": "security", "score": 0, "keywordMatches": 0, "subjectMatches": 0, "bodyMatches": 0 },
    { "intent": "out_of_office", "score": 0, "keywordMatches": 0, "subjectMatches": 0, "bodyMatches": 0 }
  ],
  "runnerUpIntent": "support",
  "runnerUpConfidence": 0.15,
  "safetyVerdict": "clean",
  "safetyAction": "deliver"
}
FieldDescription
intentThe top-scoring intent category. This is the primary signal for your agent logic.
confidenceScore between 0 and 1 for the top intent.
suggestedActionRecommended routing action (see Routing actions).
safetyVerdictSafety classification result (see Safety classification).
safetyActionAction the safety system recommends: deliver, quarantine, or reject.
flagsArray of safety flags that may require attention (see Safety flags).
runnerUpIntentSecond-highest scoring intent. Present when a runner-up scores above 0.
runnerUpConfidenceScore of the runner-up intent.

Understanding allScores

The allScores array contains scores for all 8 intent categories, sorted by score descending. Each entry includes:

FieldDescription
intentThe intent category name.
scoreClassification score (0-1). Higher means stronger signal.
keywordMatchesTotal keyword hits across subject and body.
subjectMatchesKeyword hits in the subject line only.
bodyMatchesKeyword hits in the body only.

In most cases, you only need the top-level intent and confidence fields. The allScores array is useful when:

  • Competing intents: two or more intents have non-zero scores, and you want to understand ambiguity
  • Debugging: you want to see why a message was classified a certain way
  • Custom routing: you apply your own thresholds instead of using the default suggestedAction

Entries with score: 0 had no keyword matches and can be ignored.

Batch classify

Classify multiple messages in a single request:

CLI
molted classify batch --emails '[
  {"subject": "Re: Order", "body": "When does it ship?"},
  {"subject": "Thanks!", "body": "Got it, looks great."}
]'
curl
curl -X POST "https://api.molted.email/v1/agent/batch/classify-intent" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "tenant_abc123",
    "messages": [
      {"subject": "Re: Order", "bodyText": "When does it ship?"},
      {"subject": "Thanks!", "bodyText": "Got it, looks great."}
    ]
  }'

The response contains a results array with one classification per message, in the same order as the input.

Intent categories

When an inbound message is classified, it is assigned one of these intent categories:

IntentDescription
interestedRecipient expressed interest or wants to move forward.
not_nowRecipient is not interested at this time but may be later.
objectionRecipient raised a concern or objection.
supportRecipient needs help or has a support question.
billingRecipient has a billing-related question or issue.
legalMessage relates to legal matters.
securityMessage relates to a security concern.
out_of_officeAutomated out-of-office reply.
unclassifiedCould not determine a clear intent.

Each classification also includes a confidence score between 0 and 1, and a suggestedAction.

Routing actions

The classification engine suggests one of these routing actions:

ActionDescription
notify_ownerNotify the contact's assigned owner.
require_approvalHold the message until manually approved.
auto_archiveArchive the message automatically (e.g., out-of-office replies).
escalateEscalate to a human reviewer for handling.
spamRoute to the spam queue for review.

Safety classification

Inbound messages are run through a safety classifier that produces a verdict:

VerdictDescription
cleanNo threats detected.
spamUnsolicited bulk email. Routed to the dedicated spam queue.
phishingCredential harvesting attempt. Routed to approval queue for human review.
malwareDangerous content detected. Routed to approval queue.
abuseThreats or harassment. Routed to approval queue.
impersonationSpoofing or BEC attempt. Routed to approval queue.

Only spam-verdict messages go to the spam queue. All other safety-flagged messages (phishing, malware, abuse, impersonation) require human review in the approval queue.

Spam queue

Messages classified as spam are routed to a dedicated spam queue, separate from the approval queue.

List spam messages

GET https://api.molted.email/v1/override/queues/spam

Mark as not spam

Release a message from spam and move it to the inbox:

POST https://api.molted.email/v1/override/:threadId/not-spam
Request body
{
  "reason": "This is a legitimate message"
}

Delete spam

Permanently remove a spam message:

POST https://api.molted.email/v1/override/:threadId/delete-spam

Queue counts

The queue counts endpoint now includes a spam count:

GET https://api.molted.email/v1/override/queues/counts
Response
{
  "needs_approval_outbound": 3,
  "needs_approval_inbound": 1,
  "blocked_by_policy": 0,
  "high_risk": 0,
  "spam": 5
}

Report spam

Move an inbox thread to the spam queue and record feedback:

POST https://api.molted.email/v1/override/:threadId/report-spam

This action moves the thread into the spam queue and records spam feedback that improves future classification accuracy for that sender.

Spam feedback

Every time a message is marked as spam, not spam, or deleted from spam, a feedback record is created. This feedback trains the classifier to improve accuracy over time for each tenant.

Feedback effects:

  • 3+ spam reports from the same sender email: strong spam signal (+0.5) for future messages
  • 3+ spam reports from the same domain: moderate spam signal (+0.4)
  • 3+ not-spam marks for the same sender: auto-whitelists the sender

Feedback stats

View a summary of all spam feedback for your tenant:

GET https://api.molted.email/v1/override/spam-feedback/stats
Response
{
  "total": 42,
  "spamReports": 30,
  "notSpamReports": 12,
  "uniqueDomains": 8
}

Sender reputation

Molted tracks reputation for inbound sender domains. The reputation score (0-1) is computed from:

  • Positive signals: replies sent to the sender, passing SPF/DKIM/DMARC, not-spam feedback
  • Negative signals: spam classifications, spam feedback, auth failures
  • Decay: scores drift toward 0.5 (neutral) with a 30-day half-life when no activity is seen

The classifier uses reputation to adjust spam scores:

  • Score below 0.2 (known spammer): adds +0.3 to spam score
  • Score above 0.8 (trusted sender): reduces spam score by 0.2

Query sender reputation

GET https://api.molted.email/v1/override/sender-reputation?domain=example.com
Response
[
  {
    "domain": "example.com",
    "email": null,
    "totalReceived": 150,
    "spamCount": 2,
    "notSpamCount": 5,
    "repliedCount": 12,
    "authPassCount": 145,
    "authFailCount": 3,
    "reputationScore": 0.82,
    "lastSeenAt": "2026-03-25T10:00:00Z"
  }
]

Safety settings

Safety settings control tenant-level guardrails for inbound message handling. They include per-threat actions, automation flags, and spam filter rules. Settings are tenant-wide and affect all agents and API keys.

Get safety settings

CLI
molted safety get
curl
curl "https://api.molted.email/v1/agent/config/safety-settings" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "tenantId": "tenant_abc123",
  "quarantineHighInjection": true,
  "holdCriticalAnomalies": true,
  "blockCanaryViolations": true,
  "spamAction": "quarantine",
  "phishingAction": "quarantine",
  "malwareAction": "reject",
  "abuseAction": "quarantine",
  "impersonationAction": "quarantine",
  "spamThreshold": 0.5,
  "maxLinksThreshold": 5,
  "blockNoAuth": false,
  "blockedKeywords": [],
  "allowedSenders": [],
  "spamActionLowConfidence": "deliver"
}

Update safety settings

CLI
molted safety update --settings '{
  "spamThreshold": 0.3,
  "blockNoAuth": true,
  "malwareAction": "reject"
}'
curl
curl -X PUT "https://api.molted.email/v1/agent/config/safety-settings" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "spamThreshold": 0.3,
    "blockNoAuth": true,
    "malwareAction": "reject"
  }'

All fields are optional -- only include what you want to change. Unspecified fields retain their current values.

Safety automation flags

FieldTypeDefaultDescription
quarantineHighInjectionbooleantrueQuarantine messages flagged with injection_risk.
holdCriticalAnomaliesbooleantrueHold messages with critical safety anomalies for human review.
blockCanaryViolationsbooleantrueBlock messages that trigger canary token violations.

Per-threat actions

Each threat type can be set to deliver, quarantine, or reject.

FieldTypeDefaultDescription
spamActionstringquarantineAction for messages classified as spam.
phishingActionstringquarantineAction for phishing attempts.
malwareActionstringrejectAction for dangerous content.
abuseActionstringquarantineAction for threats or harassment.
impersonationActionstringquarantineAction for spoofing or BEC attempts.

Spam filter rules

FieldTypeDefaultDescription
spamThresholdnumber0.5Spam verdict threshold (0.1-1.0). Lower means more aggressive filtering.
maxLinksThresholdinteger5Max links before triggering the excessive_links signal (1-100).
blockNoAuthbooleanfalseWhen true, emails failing all auth checks (SPF+DKIM+DMARC) receive a heavy spam penalty (+0.5).
blockedKeywordsstring[][]Custom keyword blocklist (max 100 entries). Each match adds +0.4 to the spam score.
allowedSendersstring[][]Email addresses or domains that bypass spam classification entirely (max 100 entries).
spamActionLowConfidencestringdeliverAction for spam between the custom threshold and 0.5 confidence: deliver, quarantine, or reject.
Example: aggressive spam filtering
{
  "spamThreshold": 0.3,
  "maxLinksThreshold": 3,
  "blockNoAuth": true,
  "blockedKeywords": ["crypto", "investment opportunity", "wire transfer"],
  "allowedSenders": ["trusted-partner.com", "internal@mycompany.com"],
  "spamActionLowConfidence": "quarantine"
}

Rule evaluation order

  1. Allowed senders and the sender whitelist are checked first -- matching senders bypass all classification.
  2. Blocked keywords are matched case-insensitively against the combined subject + body.
  3. Block unauthenticated checks SPF, DKIM, and DMARC results.
  4. Max links threshold counts links in the body text and HTML.
  5. All signals are aggregated and compared against the spam threshold.
  6. Low-confidence spam (between threshold and 0.5) uses the low-confidence action.

Safety flags

Messages may be flagged with safety indicators that require additional attention:

FlagDescription
conflicting_intentsMultiple intent signals detected with similar scores - may need human review.
low_confidenceClassification confidence is below 0.6 - routing may be unreliable.
injection_riskPrompt injection patterns detected in the message.
adversarial_positionSubject implies one intent but body matches a different, action-oriented intent.
thread_anomalyMessage behavior deviates from the thread's established pattern.