Inbound Mailboxes API
A mailbox connects an email address to the helpdesk: Eviworx polls it, turns every mail into a record and sends replies back the same way. Every mailbox carries its own configuration — receive and send path, defaults for new tickets, limits, post-processing in the mailbox and an optional access restriction. All of it is managed under /api/inbound-mailboxes. How a mail travels through the system is described on the Email System page.
Permissions
| Permission | Allows |
|---|---|
inboundMailboxes.view | Read mailboxes and their operating state |
inboundMailboxes.create | Create a mailbox |
inboundMailboxes.edit | Change a mailbox and query the server folder list |
inboundMailboxes.delete | Delete a mailbox — critical permission (revocation takes effect immediately, denied calls are logged) |
inboundMailboxes.testConnection | Probe the receive path |
inboundMailboxes.testSmtp | Probe the send path |
inboundMailboxes.manageAccess | Set the access restriction and grant access — critical permission, because it opens the ticket visibility across all mailboxes |
tickets.changeMailbox | Hand a ticket over to another mailbox; additionally opens the option list of all active mailboxes |
Endpoints
| Method | Endpoint | Response | Permission |
|---|---|---|---|
GET | /api/inbound-mailboxes | All mailboxes — { data }, newest first; includes deactivated ones | view |
GET | /api/inbound-mailboxes/options | Lean option list — { data } with id, name, emailAddress | any login |
GET | /api/inbound-mailboxes/:id | A single mailbox | view |
POST | /api/inbound-mailboxes | Create → 201 | create |
PUT | /api/inbound-mailboxes/:id | Update — partial changes allowed | edit |
DELETE | /api/inbound-mailboxes/:id | Delete → 204 | delete |
POST | /api/inbound-mailboxes/:id/test-connection | Probe the receive path → { connected: true } | testConnection |
POST | /api/inbound-mailboxes/:id/test-smtp | Probe the send path → { connected: true } | testSmtp |
GET | /api/inbound-mailboxes/:id/folders | Folders on the server — { data } with folder paths | edit |
GET | /api/inbound-mailboxes/:id/restriction | { mailboxId, isRestricted } | view |
PUT | /api/inbound-mailboxes/:id/restriction | Switch the restriction on/off → { mailboxId, isRestricted } | manageAccess |
GET | /api/inbound-mailboxes/:id/access | { mailboxId, isRestricted, accessList } | manageAccess |
POST | /api/inbound-mailboxes/:id/access | Grant access → 201 | manageAccess |
DELETE | /api/inbound-mailboxes/:id/access/:accessId | Revoke access → 204 | manageAccess |
Reading and probing are open to API keys as well; every mutation requires a logged-in person and answers an API key with 403. The option list is the exception among the read paths: its scope is user-specific, so it is user-bound too.
The list has neither filters nor pages — there are few entries and the administration needs all of them. Deleting is a soft delete: the mailbox disappears from every response and is no longer polled; there is no restore route.
Option list
GET /options returns only id, name and emailAddress of active mailboxes and needs no permission of its own — the scope provides the protection. The for parameter decides which one:
for | Contains |
|---|---|
| omitted (default) | Mailboxes whose tickets the caller may see — the basis for filtering |
create | Mailboxes they may send from; a subset of the first set |
transfer | all active mailboxes as handover targets — deliberately not limited to your own visibility and therefore gated with tickets.changeMailbox |
Any other value for for is refused with 400 instead of silently falling back to the default: a typo in an integration should stand out rather than return a narrower list than intended. Unrestricted mailboxes are always included.
The mailbox object
Identity and paths
| Field | Meaning |
|---|---|
name | Display name, 1–100 characters |
emailAddress | The mailbox address; unique system-wide (409 if taken) |
protocol | IMAP · MS_GRAPH — receive path |
receiveConfig | Connection details of the receive path, matching the protocol |
sendProtocol | SMTP · MS_GRAPH — send path |
sendConfig | Connection details of the send path; an empty object means the mailbox only receives |
fromName | Sender name; empty ⇒ the application name from the UI settings |
replyToAddress | Reply-to address; empty ⇒ the mailbox address |
hasReceiveCredentials · hasSendCredentials | Is a password or client secret stored? The secrets themselves are never read back |
signatureId | Signature appended to outgoing mails of this mailbox |
checkIntervalMin | Poll interval in minutes, 1–60 (default 5) |
isActive | Is polled and may send. A deactivated mailbox fetches nothing and refuses sending with 400 SOURCE_MAILBOX_INACTIVE |
What becomes of a mail
| Field | Meaning |
|---|---|
mode | TICKET always a ticket · EMAIL_CONVERSATION an email conversation · AUTO ticket if the sender has an account, otherwise a conversation. The response always shows the configured value, never the one resolved per sender |
unknownSenderPolicy | AUTO_CREATE create a contact · CATCH_ALL attribute everything to one collective account · REJECT reject |
catchAllUserId | The collective account; required with CATCH_ALL (otherwise 400) |
defaultCategoryId · defaultGroupId · defaultPriority | Defaults for new tickets. The group must handle tickets (otherwise 400), priority from LOW, MEDIUM, HIGH, URGENT, CRITICAL |
subjectPrefix | Tag in the subject, 1–10 characters; the subject then carries [tag-ticketnumber] |
autoReplyEnabled | Acknowledgement to the sender |
enforceSpf · enforceDkim · enforceDmarc | Enforce sender checks; a failed check leads to rejection |
bounceDetection | Switch for handling bounce and out-of-office replies on this mailbox |
Post-processing in the mailbox
| Field | Meaning |
|---|---|
processedAction | MARK_READ · MOVE · DELETE — what happens to a processed mail in the mailbox |
processedFolder | Target folder for MOVE; required in that case (otherwise 400) |
rejectedFolder | Folder for rejected mails, default Rejected. Rejected mails are moved, never deleted — without a folder only marking as read remains |
Limits per mailbox
| Field | Default | Effect |
|---|---|---|
rateLimitPerMinute | 60 | Mails per minute from this mailbox, 1–1000 |
rateLimitPerSenderPerHour | 30 | Mails per sender and hour, 1–1000 |
autoCreateDailyLimit | 100 | Automatically created contacts per day, 1–10000. When the mailbox hits the limit, the creation path answers 429 with a Retry-After until midnight (UTC) — the mail stays open and is processed afterwards |
Operating state (read-only)
| Field | Meaning |
|---|---|
lastCheckedAt | Last poll attempt |
lastSuccessfulCheckAt | Last successful poll; stays put when an error occurs |
lastErrorCode | Reason of the last error as a code (see below); null means no error. The code also stays set when only the post-processing of a single mail failed |
consecutiveErrors | Consecutive errors; 0 after a success |
openMailCount | Backlog: discovered mails not yet completed |
oldestOpenSince | Since when the oldest open mail has been waiting |
accessRestricted | Is the access restriction active? |
Every poll rewrites these fields — they heal themselves. The system status evaluates the same state: a mailbox without polls, one with errors and one with too old a backlog each report their own reason.
Receive and send configuration
| Case | Fields | Defaults |
|---|---|---|
receiveConfig, IMAP |
host, port, security (none · tls · ssl), username, password, folder, tlsVerify |
port 993, security ssl, folder INBOX, tlsVerify true |
receiveConfig, MS_GRAPH |
tenantId, clientId, clientSecret, userPrincipal, folder |
folder inbox |
sendConfig, SMTP |
host, port, security, username (optional), password, tlsVerify |
port 587, security tls, tlsVerify true |
sendConfig, MS_GRAPH |
tenantId, clientId, clientSecret, userPrincipal |
— |
Password and client secret only go in, never out: they are stored encrypted, and the response only shows whether one is present. If you send no secret when updating, the stored one is kept. tenantId and clientId are Azure identifiers, userPrincipal is an email address.
Folder paths
Receive folder, folder for processed mails and folder for rejected mails are written the same way: as display names, nested levels separated by a slash — Support/Done. That notation applies to both protocols; translating it into the separators and namespaces of the respective server is Eviworx's job. Common names such as INBOX or inbox are recognised regardless of case. The receive folder must exist — it is only looked up, never created; the target folders for processed and rejected mails are created by Eviworx when needed. The folder list shows what the server offers.
Creating and updating
- Both paths accept known fields only — an unknown field is refused with 400 instead of being silently ignored.
- The configuration is validated against the chosen protocol: an IMAP mailbox needs IMAP fields, a Graph mailbox needs Graph fields. Error messages name the field path, for instance receiveConfig.host.
- If the send configuration is missing or empty when creating, the mailbox only receives. There is no silent fallback to a global send path.
- A partial update changes exactly the fields sent and resets nothing else. Configuration objects may also come partially and are merged with what is stored.
- Changing the protocol requires sending the matching configuration (otherwise 400) — and it is then not merged with the old one. That closes the gap "new protocol, old credentials".
- An empty send configuration on update removes sending: the mailbox then only receives.
- Dependencies are checked against the result, not the request: a collective account must be present even when only the sender policy is changed.
Ability to send
Whether a mailbox can send is decided by one rule for all paths — connection probe, ticket reply and "ticket as email". It follows what sending actually requires:
| State | Result |
|---|---|
| no send configuration | RECEIVE_ONLY |
| SMTP without a user name | able to send — a relay without authentication is a valid setup |
| SMTP with a user name, password stored | able to send |
| SMTP with a user name, no password | NO_CREDENTIALS |
| Microsoft Graph with a client secret | able to send |
| Microsoft Graph without a client secret | NO_CREDENTIALS |
If a mailbox cannot send, the send paths answer 400 MAILBOX_SEND_NOT_CONFIGURED and name the reason in details.reason — before a message is created, so that no "reply sent" trail exists for a mail that never left. The connection probe deliberately checks only the configuration, not the active switch: a mailbox can be probed before it is activated. On a ticket, sendConfigured in the mailbox reference carries the same value the gate uses — the UI can disable the reply button with it instead of waiting for the error.
Probes: connection and folder list
Both probes run over the same path as production: the same credentials, the same adapter, the same folder resolution. A probe therefore really confirms the production path and not a separate test connection.
POST /api/inbound-mailboxes/:id/test-connection
POST /api/inbound-mailboxes/:id/test-smtp
GET /api/inbound-mailboxes/:id/folders
{ "connected": true }
{ "data": ["INBOX", "Support/Erledigt", "Rejected"] }
- A failure is an error, not a response with
connected: false: status 400, and the reason of the probe is itself theerrorCode(theMAIL_*codes below).details.messagecarries an English diagnosis for support. - If credentials are missing or the mailbox is not set up for sending at all, Eviworx answers 400 right away — without contacting the mail server.
- If the email service does not answer within 20 seconds, that is an infrastructure case and not a mail error:
503 EMAIL_WORKER_UNAVAILABLE. The probe itself has a tighter deadline so the caller sees the diagnosis rather than the timeout. - The folder list carries the
editpermission, notview: it supplies data for the edit form.
For global sending without a mailbox context, the two probes of the Settings API apply (/api/settings/email/test-smtp and /test-graph) — same response shape, same error codes.
Access restriction
By default a mailbox is open: whoever may see tickets also sees the tickets of that mailbox. A restricted mailbox inverts this — only people with a grant then see its tickets. This is the way to handle mailboxes such as hr@ or billing@ whose records are not for the whole team.
| Grant | Meaning |
|---|---|
userId · roleId · agentGroupId | Exactly one of them per grant: a person, everyone with a role, or an agent group. The UI offers person and role; the group grant is an API-only path |
canViewTickets | May see the tickets of this mailbox |
canBeAssigned | May work on them and send from them |
- A second grant to the same target is refused with 409.
- Revoking a grant that does not exist and revoking a grant belonging to another mailbox answer identically (
404 MAILBOX_ACCESS_ENTRY_NOT_FOUND) — the API does not reveal whether a foreign entry exists. - The manageAccess permission itself overrides every restriction: whoever holds it sees the tickets of every mailbox and can be assigned to them. That is why it is a critical permission.
Error codes
| Code | HTTP | When |
|---|---|---|
MAILBOX_NOT_FOUND | 404 | Unknown or deleted mailbox |
MAILBOX_EMAIL_EXISTS | 409 | Address already taken; details names the address |
MAILBOX_CATCH_ALL_USER_REQUIRED | 400 | Sender policy CATCH_ALL without a collective account |
MAILBOX_PROCESSED_FOLDER_REQUIRED | 400 | Post-processing MOVE without a target folder |
AGENT_GROUP_NOT_FOUND | 404 | Default group does not exist |
GROUP_ENTITY_TYPE_MISMATCH | 400 | Default group does not handle tickets |
TICKET_CATEGORY_NOT_FOUND | 404 | Default category does not exist |
MAILBOX_RECEIVE_NOT_CONFIGURED | 400 | Receive probe or folder list without stored credentials |
MAILBOX_SEND_NOT_CONFIGURED | 400 | Mailbox cannot send; details.reason names RECEIVE_ONLY or NO_CREDENTIALS |
SOURCE_MAILBOX_INACTIVE | 400 | Sending from a deactivated mailbox |
MAILBOX_ACCESS_ENTRY_NOT_FOUND | 404 | Grant entry does not belong to this mailbox or does not exist |
USER_CREATION_LIMIT_EXCEEDED | 429 | Daily limit of automatically created contacts reached; Retry-After until midnight (UTC) |
EMAIL_WORKER_UNAVAILABLE | 503 | The email service did not answer the probe |
EMAIL_SYSTEM_DISABLED | 400 | Global probes only: the email channel is not enabled |
VALIDATION_ERROR | 400 | Schema violation; details lists the affected field paths |
FORBIDDEN | 403 | Permission missing — or an API key calls a user-bound path |
Reasons of a mail error
The same seventeen codes appear in two places: as the errorCode of a failed probe and as lastErrorCode on the mailbox. A glance at the list therefore says the same thing as a probe.
| Code | Meaning |
|---|---|
MAIL_CONNECTION_FAILED | Server unreachable (name or connection) |
MAIL_TIMEOUT | Timeout exceeded |
MAIL_TLS_FAILED | TLS or certificate refused |
MAIL_AUTH_FAILED | Login refused |
MAIL_CREDENTIALS_MISSING | No password or secret stored |
MAIL_PERMISSION_DENIED | The app permission in Microsoft 365 is insufficient |
MAIL_MAILBOX_NOT_FOUND | The given mailbox does not exist there |
MAIL_FOLDER_NOT_FOUND | Folder cannot be resolved or created |
MAIL_RATE_LIMITED | The mail server is throttling |
MAIL_RECIPIENT_REJECTED | Recipient refused |
MAIL_MESSAGE_TOO_LARGE | Message too large for the server |
MAIL_MESSAGE_REJECTED | Message or sender refused |
MAIL_CONFIG_UNAVAILABLE | Mailbox inactive or without the required path |
MAIL_QUEUE_UNAVAILABLE | The job could not be queued |
MAIL_SEND_FAILED | Sending failed without a more specific reason |
MAIL_RECEIVE_FAILED | Polling failed without a more specific reason |
MAIL_SEND_OUTCOME_UNKNOWN | The attempt broke off — the mail may be out |
Audit trail
| Operation | Entry |
|---|---|
| Create | CREATE — with receive and send protocol |
| Update | UPDATE — old/new for each of the 26 audited single fields; of the configurations only the fact that they were touched is recorded, never their content |
| Delete | DELETE |
| Grant / revoke access | MAILBOX_ACCESS_GRANTED · MAILBOX_ACCESS_REVOKED — with target and both flags |
| Switch restriction on/off | MAILBOX_RESTRICTION_ENABLED · MAILBOX_RESTRICTION_DISABLED — only on a real change |
Every change to a mailbox reaches the email service immediately: it reloads the mailboxes without waiting for the next poll. A deactivated mailbox therefore stops fetching mails right away.
Related pages
- Email System — the path of a mail in and out: polling, rejection, backlog, sending and limits in context
- Tickets API — email thread, replying by mail and the mailbox fields on a ticket
- Email Signatures API — the signatures a mailbox can append
- Settings API — the global send path and the channel settings
- Permissions & RBAC — how mailbox grants interact with ticket visibility