openapi: 3.1.0 info: description: >- The API of mailcow, the mail server suite with antispam, antivirus and a web UI. **API keys**: create them in the mailcow UI under System > Configuration > Access > Administrators, card API. A key works from its allowed IP addresses (or from anywhere if the IP check is skipped). Read-only keys may use the `get` routes only. Keys set in mailcow.conf (`API_KEY`, `API_KEY_READ_ONLY`, `API_ALLOW_FROM`) are shown in the UI but can only be changed in mailcow.conf. A key acts as an administrator. **Requests**: `get` routes use GET, all others POST with `Content-Type: application/json`. - add: the new object as body - edit: `{"items": [...], "attr": {...}}`, `items` are the objects to change, `attr` the values to set - delete: the list of objects to delete **Answers**: write routes return the list of messages of the call (`type`, `msg`), or `{"type": "success", "msg": "Task completed"}` / `{"type": "error", "msg": "Cannot add item"}` if there are none. The status is 200 for failures too, so check `type`. Read routes return the object or list, `{}` or `[]` if there is nothing. Unknown routes answer 404, invalid JSON 400, a wrong method 405. title: mailcow API version: "1.0.0" servers: - url: / components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key schemas: Message: type: object description: >- One message of a write call, as the mailcow UI shows it. `msg` is a key of the mailcow language files, alone or as a list with the values of its placeholders. properties: type: type: string enum: - success - danger - warning - info log: type: array description: >- The call that produced the message (function, action, object, data), secrets replaced by `*` items: {} msg: oneOf: - type: string - type: array items: {} required: - type - msg Messages: type: array items: $ref: "#/components/schemas/Message" TaskResult: type: object description: Answer of a write call that produced no message properties: type: type: string enum: - success - error msg: type: string examples: - Task completed - Cannot add item required: - type - msg Error: type: object properties: type: type: string const: error msg: type: string required: - type - msg Domain: type: object description: >- A domain. Quotas and sizes are in bytes; the `*_int` fields repeat the value before them. properties: domain_name: type: string description: Domain name (IDN as punycode) domain_h_name: type: string description: Domain name in Unicode description: type: string description: Description max_new_mailbox_quota: type: integer description: >- Largest quota a new mailbox can get: the free domain quota, at most the max. mailbox quota def_new_mailbox_quota: type: integer description: Quota a new mailbox gets by default quota_used_in_domain: type: [string, integer] description: Sum of the quotas of the mailboxes bytes_total: type: [string, integer] description: Storage used by the mailboxes msgs_total: type: [string, integer] description: Number of messages in the mailboxes mboxes_in_domain: type: integer description: Number of mailboxes mboxes_left: type: integer description: Mailboxes that can still be added max_num_aliases_for_domain: type: integer description: Max. number of aliases max_num_mboxes_for_domain: type: integer description: Max. number of mailboxes def_quota_for_mbox: type: integer description: Default quota of new mailboxes max_quota_for_mbox: type: integer description: Max. quota per mailbox max_quota_for_domain: type: integer description: Quota of the whole domain relayhost: type: [string, integer] description: ID of the sender-dependent transport, "0" = none backupmx: type: integer enum: [0, 1] description: Relay domain (backup MX) backupmx_int: type: integer enum: [0, 1] gal: type: integer enum: [0, 1] description: Global address list in SOGo gal_int: type: integer enum: [0, 1] rl: description: Rate limit, `false` if none oneOf: - $ref: "#/components/schemas/DomainRatelimit" - type: boolean const: false active: type: integer enum: [0, 1] description: Domain active active_int: type: integer enum: [0, 1] relay_all_recipients: type: integer enum: [0, 1] description: Relay all recipients relay_all_recipients_int: type: integer enum: [0, 1] relay_unknown_only: type: integer enum: [0, 1] description: Relay non-existing mailboxes only relay_unknown_only_int: type: integer enum: [0, 1] created: type: string description: Creation time (`YYYY-MM-DD hh:mm:ss`) modified: type: [string, "null"] description: Time of the last change aliases_in_domain: type: [integer, string] description: Number of aliases, including those of its alias domains aliases_left: type: integer description: Aliases that can still be added domain_admins: type: string description: Comma-separated domain admins, `-` if none; admins only tags: type: array items: type: string description: Tags; missing when the domain has none DomainRatelimit: type: object description: Rate limit of a domain or alias domain properties: value: type: string description: Messages per time frame frame: type: string enum: [s, m, h, d] description: Time frame (second, minute, hour, day) DomainTemplate: type: object properties: id: type: integer description: Template ID template: type: string description: Template name type: type: string const: domain attributes: $ref: "#/components/schemas/DomainTemplateAttributes" created: type: string description: Creation time modified: type: [string, "null"] description: Time of the last change DomainTemplateAttributes: type: object description: Values of a domain template as stored; quotas in bytes properties: tags: type: array items: type: string max_num_aliases_for_domain: type: integer max_num_mboxes_for_domain: type: integer def_quota_for_mbox: type: integer max_quota_for_mbox: type: integer max_quota_for_domain: type: integer rl_frame: type: string enum: [s, m, h, d] rl_value: type: [string, integer] description: Rate limit, "" = none active: type: integer enum: [0, 1] gal: type: integer enum: [0, 1] backupmx: type: integer enum: [0, 1] relay_all_recipients: type: integer enum: [0, 1] relay_unknown_only: type: integer enum: [0, 1] dkim_selector: type: string key_size: type: integer DomainTemplateInput: type: object description: >- Values of a domain template, quotas in MiB. The defaults apply when a template is added; for edit/domain/template see there. properties: template: type: string description: Template name, unique tags: type: array items: type: string default: [] description: Tags of new domains max_num_aliases_for_domain: type: [integer, string] default: 400 description: Max. number of aliases max_num_mboxes_for_domain: type: [integer, string] default: 10 description: Max. number of mailboxes def_quota_for_mbox: type: [integer, string] default: 3072 description: Default quota of new mailboxes in MiB max_quota_for_mbox: type: [integer, string] default: 10240 description: Max. quota per mailbox in MiB max_quota_for_domain: type: [integer, string] default: 10240 description: Quota of the whole domain in MiB rl_value: type: [integer, string] default: "" description: Rate limit, messages per `rl_frame`; empty = none rl_frame: type: string enum: [s, m, h, d] default: s description: Rate limit time frame active: type: [integer, string] enum: [0, 1, "0", "1"] default: 1 gal: type: [integer, string] enum: [0, 1, "0", "1"] default: 1 description: Global address list in SOGo backupmx: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: Relay domain (backup MX) relay_all_recipients: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 relay_unknown_only: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 dkim_selector: type: string default: dkim description: Selector of the DKIM key of new domains key_size: type: [integer, string] default: 2048 description: DKIM key size in bits of new domains AliasDomain: type: object properties: alias_domain: type: string description: Alias domain name target_domain: type: string description: Domain the alias domain points to parent_is_backupmx: type: integer enum: [0, 1] description: The target domain is a relay domain active: type: integer enum: [0, 1] description: Alias domain active active_int: type: integer enum: [0, 1] rl: description: Rate limit, `false` if none oneOf: - $ref: "#/components/schemas/DomainRatelimit" - type: boolean const: false created: type: string description: Creation time modified: type: [string, "null"] description: Time of the last change DomainPolicyEntry: type: object properties: object: type: string description: The domain or mailbox the entry belongs to value: type: string description: Sender address or pattern prefid: type: integer description: Entry ID (for delete/domain-policy) DkimKey: type: object properties: pubkey: type: string description: Public key (base64, without PEM lines) length: type: string enum: ["1024", "2048", "3072", "4096", ">= 8192"] description: Key size in bits, estimated from the public key dkim_txt: type: string description: >- Content of the DNS TXT record; split into quoted strings of 255 characters when `SPLIT_DKIM_255` is enabled dkim_selector: type: string description: Selector privkey: type: string description: >- Private key in PEM format, base64-encoded, when `SHOW_DKIM_PRIV_KEYS` is enabled, else empty DomainSearchRequest: type: object description: >- Server-side processing parameters of DataTables (https://datatables.net/manual/server-side). Without `start` and `length` all matching domains are answered. properties: draw: type: integer description: Request counter, answered as it is start: type: integer description: Offset of the first domain length: type: integer description: Number of domains, -1 = all search: type: object properties: value: type: string description: Searched in all columns with `searchable` true order: type: array items: type: object properties: column: type: integer description: Position in `columns` (see the description of the route) dir: type: string enum: [asc, desc] columns: type: array description: >- The columns of the table; the position gives the database column (see the description of the route) items: type: object properties: data: type: [string, integer] description: >- Column name of the UI; a column position makes `search.value` of this entry filter that column searchable: type: [boolean, string] description: Column takes part in the global search; must be set orderable: type: [boolean, string] description: Column may be sorted by; must be set search: type: object properties: value: type: string description: Filter of this column DomainSearchResult: type: object properties: draw: type: integer description: "`draw` of the request" recordsTotal: type: integer description: Number of domains the caller can see recordsFiltered: type: integer description: Number of domains that match the search data: type: array description: The domains of the page items: $ref: "#/components/schemas/Domain" MailboxItems: description: One mailbox address or a list of them oneOf: - type: string - type: array items: type: string UserAclName: type: string description: "A user ACL: something the mailbox user may do in the UI" enum: - spam_alias - tls_policy - spam_score - spam_policy - delimiter_action - syncjobs - eas_reset - sogo_profile_reset - pushover - quarantine - quarantine_attachments - quarantine_notification - quarantine_category - app_passwds - pw_reset ProtocolAccessName: type: string enum: - imap - pop3 - smtp - sieve - eas - dav MailboxAttributes: type: object description: Settings of a mailbox; flags are "0" or "1" properties: force_pw_update: type: [string, integer] description: The user must change the password at the next login force_tfa: type: [string, integer] description: The user must set up two-factor authentication at the next login tls_enforce_in: type: [string, integer] tls_enforce_out: type: [string, integer] sogo_access: type: [string, integer] description: Login to SOGo from the UI imap_access: type: [string, integer] pop3_access: type: [string, integer] smtp_access: type: [string, integer] sieve_access: type: [string, integer] eas_access: type: [string, integer] dav_access: type: [string, integer] relayhost: type: [string, integer] description: ID of the sender-dependent transport, "0" for none shared: type: [string, integer] description: Shared mailbox without a login of its own passwd_update: type: [string, integer] description: Time of the last password change mailbox_format: type: string quarantine_notification: type: string enum: - never - hourly - daily - weekly quarantine_category: type: string enum: - reject - add_header - all attribute_hash: type: string description: Hash of the template the settings came from, cleared by manual changes recovery_email: type: string description: Address for password reset mails (present after it was set) template: type: string description: Name of the template the mailbox was created from (if any) Mailbox: type: object description: >- A mailbox. The reduced form lacks `max_new_quota`, `spam_aliases`, `pushover_active`, `rl`, `rl_scope`, `is_relayed` and `sender_acl`; `tags` is missing without tags. properties: username: type: string description: Address of the mailbox active: type: integer description: 1 active, 0 inactive, 2 login disabled (mail is still accepted) active_int: type: integer description: Same as `active` domain: type: string name: type: string description: Full name local_part: type: string quota: type: integer description: Quota in bytes, 0 = unlimited messages: type: integer description: Number of messages attributes: $ref: "#/components/schemas/MailboxAttributes" custom_attributes: type: [object, array] description: Custom attributes (an empty list when there are none) additionalProperties: type: string quota_used: type: integer description: Used bytes percent_in_use: type: [integer, string] description: Used part of the quota in percent, "- " for unlimited quota created: type: string modified: type: [string, "null"] authsource: type: string enum: - mailcow - keycloak - generic-oidc - ldap percent_class: type: string enum: - info - success - warning - danger description: info (unlimited), success, warning (≥ 75 %), danger (≥ 90 %) last_imap_login: type: integer description: Unix time of the last IMAP login, 0 = none last_smtp_login: type: integer last_pop3_login: type: integer last_sso_login: type: integer last_sogo_login: type: integer max_new_quota: type: integer description: Largest quota in bytes the mailbox may get (domain limits) spam_aliases: type: integer description: Number of valid time-limited aliases pushover_active: type: integer enum: [0, 1] rl: description: Effective rate limit, `false` if there is none oneOf: - $ref: "#/components/schemas/MailboxRatelimit" - type: boolean const: false rl_scope: type: string enum: - mailbox - domain description: Whether `rl` is the mailbox's own limit or the domain limit is_relayed: type: integer description: 1 if the domain is relayed (backup MX) sender_acl: type: array description: Internal addresses and @domains the mailbox may send as items: type: string tags: type: array items: type: string MailboxAdd: type: object required: - local_part - domain properties: local_part: type: string description: Part before the @ domain: type: string description: Domain of the mailbox name: type: string description: Full name (`<` and `>` at the ends are removed) authsource: type: string enum: - mailcow - keycloak - generic-oidc - ldap default: mailcow description: Login source; an external one only if it is the configured identity provider, else mailcow password: type: string format: password description: Checked against the password policy; empty (with `password2`) for a shared mailbox password2: type: string format: password description: The password again template: type: [integer, string] description: ID of the mailbox template for the defaults (default the first) quota: type: [integer, string] description: Quota in MiB, 0 = unlimited active: type: [integer, string] enum: [0, 1, 2, "0", "1", "2"] description: 1 active, 0 inactive, 2 login disabled (mail is accepted) tags: type: array items: type: string description: Tags (the first 26 are saved) protocol_access: type: array description: Allowed protocols; when sent it replaces the single `*_access` fields items: $ref: "#/components/schemas/ProtocolAccessName" imap_access: type: [integer, string] enum: [0, 1, "0", "1"] pop3_access: type: [integer, string] enum: [0, 1, "0", "1"] smtp_access: type: [integer, string] enum: [0, 1, "0", "1"] sieve_access: type: [integer, string] enum: [0, 1, "0", "1"] eas_access: type: [integer, string] enum: [0, 1, "0", "1"] dav_access: type: [integer, string] enum: [0, 1, "0", "1"] sogo_access: type: [integer, string] enum: [0, 1, "0", "1"] description: Login to SOGo from the UI force_pw_update: type: [integer, string] enum: [0, 1, "0", "1"] description: Password change at the first login (always 0 for external sources) force_tfa: type: [integer, string] enum: [0, 1, "0", "1"] description: Two-factor setup at the first login (always 0 for generic-oidc) tls_enforce_in: type: [integer, string] enum: [0, 1, "0", "1"] tls_enforce_out: type: [integer, string] enum: [0, 1, "0", "1"] relayhost: type: [integer, string] default: 0 description: ID of a sender-dependent transport, 0 = none shared: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: Shared mailbox without a login of its own, opened by group members quarantine_notification: type: string enum: - never - hourly - daily - weekly quarantine_category: type: string enum: - reject - add_header - all tagged_mail_handler: type: string enum: - subfolder - subject - none description: Handling of mail to address+tag, see `edit/delimiter_action` acl: type: array description: User ACLs to grant; when sent, all others are off items: $ref: "#/components/schemas/UserAclName" rl_value: type: [integer, string] description: Rate limit, messages per `rl_frame` (0 or empty = none) rl_frame: type: string enum: - s - m - h - d attribute_hash: type: string description: Internal, the hash of the template the values come from MailboxEdit: type: object properties: active: type: [integer, string] enum: [0, 1, 2, "0", "1", "2"] description: 1 active, 0 inactive, 2 login disabled (mail is accepted) name: type: string description: Full name; empty keeps the current name quota: type: [integer, string] description: Quota in MiB, 0 = unlimited; empty keeps the current quota password: type: string format: password description: New password (authsource mailcow), checked against the password policy password2: type: string format: password authsource: type: string enum: - mailcow - keycloak - generic-oidc - ldap description: An external source only if it is the configured identity provider pw_recovery_email: type: string description: Address for password reset mails (authsource mailcow only) force_pw_update: type: [integer, string] enum: [0, 1, "0", "1"] force_tfa: type: [integer, string] enum: [0, 1, "0", "1"] sogo_access: type: [integer, string] enum: [0, 1, "0", "1"] protocol_access: type: array description: Allowed protocols; when sent it replaces the single `*_access` fields items: $ref: "#/components/schemas/ProtocolAccessName" imap_access: type: [integer, string] enum: [0, 1, "0", "1"] pop3_access: type: [integer, string] enum: [0, 1, "0", "1"] smtp_access: type: [integer, string] enum: [0, 1, "0", "1"] sieve_access: type: [integer, string] enum: [0, 1, "0", "1"] eas_access: type: [integer, string] enum: [0, 1, "0", "1"] dav_access: type: [integer, string] enum: [0, 1, "0", "1"] relayhost: type: [integer, string] description: ID of a sender-dependent transport, 0 = none shared: type: [integer, string] enum: [0, 1, "0", "1"] tags: type: array items: type: string description: Tags to add; existing tags stay (remove with `delete/mailbox/tag/{mailbox}`) tagged_mail_handler: type: string enum: - subfolder - subject - none sender_acl: description: >- Replaces the internal addresses and @domains the mailbox may send as; `*` (admins only) allows all, `["default"]` removes all oneOf: - type: string - type: array items: type: string extended_sender_acl: type: string description: Replaces the external sender addresses or domains, separated by space, comma or semicolon attribute_hash: type: string description: Internal; cleared when not sent MailboxTemplateInput: type: object properties: quota: type: [integer, string] default: 0 description: Quota in MiB, 0 = unlimited tags: type: array items: type: string tagged_mail_handler: type: string enum: - subfolder - subject - none default: none quarantine_notification: type: string enum: - never - hourly - daily - weekly default: hourly quarantine_category: type: string enum: - reject - add_header - all default: reject rl_value: type: [integer, string] description: Rate limit, messages per `rl_frame` rl_frame: type: string enum: - s - m - h - d default: s force_pw_update: type: [integer, string] enum: [0, 1, "0", "1"] force_tfa: type: [integer, string] enum: [0, 1, "0", "1"] sogo_access: type: [integer, string] enum: [0, 1, "0", "1"] active: type: [integer, string] enum: [0, 1, 2, "0", "1", "2"] default: 1 tls_enforce_in: type: [integer, string] enum: [0, 1, "0", "1"] tls_enforce_out: type: [integer, string] enum: [0, 1, "0", "1"] protocol_access: type: array items: $ref: "#/components/schemas/ProtocolAccessName" description: Allowed protocols (default all) acl: type: array items: $ref: "#/components/schemas/UserAclName" description: User ACLs granted to new mailboxes MailboxTemplate: type: object properties: id: type: integer template: type: string description: Name type: type: string const: mailbox attributes: type: object description: The settings as in the example; quota in bytes, one `acl_` flag per user ACL additionalProperties: true created: type: string modified: type: [string, "null"] Resource: type: object properties: name: type: string description: Address of the resource kind: type: string enum: - location - group - thing multiple_bookings: type: integer description: 0 always free, -1 unlimited but busy when booked, n ≥ 1 at most n bookings description: type: string active: type: integer active_int: type: integer domain: type: string local_part: type: string AppPassword: type: object properties: id: type: integer name: type: string mailbox: type: string domain: type: string password: type: string description: Hash of the app password created: type: string modified: type: [string, "null"] imap_access: type: integer smtp_access: type: integer dav_access: type: integer eas_access: type: integer pop3_access: type: integer sieve_access: type: integer active: type: integer SieveFilter: type: object properties: active: type: integer enum: [0, 1] id: type: integer username: type: string description: Mailbox filter_type: type: string enum: - prefilter - postfilter script_data: type: string description: The Sieve script script_desc: type: string TimeLimitedAlias: type: object properties: address: type: string goto: type: string description: Mailbox the alias delivers to description: type: string validity: type: integer description: Unix time of expiry (0 when made permanent by an edit) created: type: string modified: type: [string, "null"] permanent: type: integer enum: [0, 1] SpamPolicyEntry: type: object properties: object: type: string description: Mailbox or domain the entry belongs to value: type: string description: Sender address, domain or pattern prefid: type: integer description: ID for `delete/mailbox-policy` MailboxRatelimit: type: object properties: value: type: string description: Number of messages frame: type: string enum: - s - m - h - d description: Per second, minute, hour or day SpamScore: type: object properties: score: type: string description: '"low,high": junk folder from low, rejected from high' LastLogin: type: object properties: ui: description: Previous successful UI login, `false` if there is none, `[]` for domain admins oneOf: - type: object properties: remote: type: string description: IP address time: type: integer description: Unix time - type: boolean const: false - type: array maxItems: 0 sasl: type: array items: type: object properties: real_rip: type: string description: Client IP; private and internal addresses as "Web/EAS/Internal (address)" datetime: type: string service: type: string description: e.g. imap, smtp, pop3, SOGO, SSO, MAILCOWUI app_password: type: integer description: ID of the app password used, 0 = none app_password_name: type: [string, "null"] location: type: string description: Country code of public addresses (if known) MailboxSearchRequest: type: object description: DataTables server-side request properties: draw: type: integer description: Counter, returned unchanged start: type: integer description: Offset of the first row; without it all rows are returned length: type: integer description: Rows per page, -1 = all search: type: object properties: value: type: string description: Searched in all searchable columns (substring) order: type: array items: type: object properties: column: type: integer description: Column number (index in `columns`) dir: type: string enum: - asc - desc columns: type: array description: Column n of the table is `columns[n]`; needed to search or sort items: type: object properties: data: type: [string, integer] description: >- Name of the column in the UI; for this column's `search.value` only a column number works, other values filter the address searchable: type: [boolean, string] description: true or "true" includes the column in the search orderable: type: [boolean, string] description: true or "true" allows sorting by the column search: type: object properties: value: type: string description: Filter for this column only (substring) MailboxSearchResult: type: object properties: draw: type: integer recordsTotal: type: integer recordsFiltered: type: integer data: type: array items: $ref: "#/components/schemas/Mailbox" Alias: type: object properties: in_primary_domain: type: string description: Target domain if `domain` is an alias domain, else empty id: type: integer domain: type: string description: Domain of the address, a domain or alias domain public_comment: type: [string, "null"] description: Comment shown to the users private_comment: type: [string, "null"] description: Comment for administrators goto: type: string description: >- Comma-separated destination addresses, or `null@localhost` (discard), `spam@localhost` (learn as spam), `ham@localhost` (learn as ham) address: type: string description: Alias address, `@example.org` for a catch-all is_catch_all: type: integer description: 1 = catch-all of the domain internal: type: integer description: 1 = only reachable from its own domain and its alias domains active: type: integer description: 1 = active, 0 = inactive active_int: type: integer description: Same as `active` sogo_visible: type: integer description: 1 = selectable sender in SOGo sogo_visible_int: type: integer description: Same as `sogo_visible` sender_allowed: type: integer description: 1 = the destination mailboxes may send as this alias group_id: type: [integer, "null"] description: >- Mailbox group whose distribution address this is; such aliases can only be changed in the group group_name: type: [string, "null"] description: Name of that mailbox group created: type: string description: Creation time, `YYYY-MM-DD hh:mm:ss` modified: type: [string, "null"] description: Time of the last change BccMap: type: object properties: id: type: integer local_dest: type: string description: Domain as `@example.org` or the address of a mailbox or alias bcc_dest: type: string description: Address that gets the copies active: type: integer description: 1 = active, 0 = inactive type: type: string enum: - sender - rcpt description: "`sender`: mail sent by `local_dest`; `rcpt`: mail sent to it" created: type: string domain: type: string description: Domain of `local_dest` modified: type: [string, "null"] RecipientMap: type: object properties: id: type: integer recipient_map_old: type: string description: Original recipient, an address or `@domain` recipient_map_new: type: string description: New recipient, an address or `@domain` active: type: integer description: 1 = active, 0 = inactive created: type: string modified: type: [string, "null"] TlsPolicyMap: type: object properties: id: type: integer dest: type: string description: Destination policy: type: string enum: - none - may - encrypt - dane - dane-only - fingerprint - verify - secure parameters: type: [string, "null"] description: Space-separated `name=value` attributes, may be empty active: type: integer description: 1 = active, 0 = inactive created: type: string modified: type: [string, "null"] Relayhost: type: object description: A sender-dependent transport properties: id: type: integer description: The value domains and mailboxes use as `relayhost` hostname: type: string description: Next hop username: type: string description: SMTP user name, empty without authentication password: type: string description: SMTP password in clear text active: type: integer description: 1 = active, 0 = inactive password_short: type: string description: First three characters of the password and `...` used_by_domains: type: string description: Comma-separated domains that use the transport, may be empty used_by_mailboxes: type: string description: Comma-separated mailboxes that use the transport, may be empty Transport: type: object description: A transport map entry properties: id: type: integer is_mx_based: type: integer description: 1 = `destination` is a regular expression for MX names destination: type: string nexthop: type: string username: type: string description: SMTP user name, empty without authentication password: type: string description: SMTP password in clear text active: type: integer description: 1 = active, 0 = inactive password_short: type: string description: First three characters of the password and `...` ForwardingHost: type: object properties: host: type: string description: IP address or network source: type: string description: What was added (host name, domain or the address itself) keep_spam: type: string enum: - "yes" - "no" description: "`yes` = the mail of the host is not scanned for spam" RspamdSettingAttributes: type: object properties: desc: type: string description: Short description content: type: string description: Rule content in Rspamd settings syntax active: type: [boolean, integer, string] description: 1 = the rule is handed to Rspamd default: 0 required: - desc - content RspamdSetting: type: object properties: id: type: integer desc: type: string description: Short description content: type: string description: Rule content in Rspamd settings syntax active: type: integer enum: - 0 - 1 RspamdRegexMap: type: string description: File name of a global Rspamd regex map enum: - global_mime_from_blacklist.map - global_mime_from_whitelist.map - global_smtp_from_blacklist.map - global_smtp_from_whitelist.map - global_rcpt_blacklist.map - global_rcpt_whitelist.map - fishy_tlds.map - bad_words.map - bad_words_de.map - bad_languages.map - bulk_header.map - bad_header.map - monitoring_nolog.map Preset: type: object properties: name: type: string description: File name of the preset without `.yml` headline: type: string description: Title, translated content: type: string description: Rspamd settings rule or Sieve script GlobalFilters: type: object properties: prefilter: type: string description: Sieve script that runs before the filters of the mailboxes postfilter: type: string description: Sieve script that runs after the filters of the mailboxes MailQueueItem: type: object description: One message of `postqueue -j` properties: queue_name: type: string description: Queue, e.g. `active`, `deferred`, `hold`, `incoming` queue_id: type: string arrival_time: type: integer description: Unix time message_size: type: integer description: Size in bytes forced_expire: type: boolean sender: type: string recipients: type: array description: Recipient addresses, with the reason of the delay in brackets if there is one items: type: string QuarantineItem: type: object properties: id: type: integer qid: type: string description: Postfix queue ID of the message subject: type: string virus_flag: type: integer description: Greater than 0 when Rspamd found a virus (`VIRUS_FOUND`) score: type: number description: Rspamd score rcpt: type: string description: Mailbox the item belongs to sender: type: string action: type: string description: Rspamd action, e.g. `reject` or `add header` created: type: integer description: Unix time notified: type: integer description: 1 when the recipient got a notification QuarantineItemDetails: type: object properties: id: type: integer qid: type: string description: Postfix queue ID of the message subject: type: string score: type: number description: Rspamd score ip: type: string description: IP of the sending server action: type: string description: Rspamd action symbols: type: string description: Rspamd symbols as JSON text fuzzy_hashes: type: string description: Fuzzy hashes as JSON text sender: type: string rcpt: type: string description: Mailbox the item belongs to msg: type: string description: The raw message domain: type: [string, "null"] notified: type: integer description: 1 when the recipient got a notification created: type: string description: Time of quarantining (`YYYY-MM-DD HH:MM:SS`) user: type: string description: Authenticated sender, `unknown` if none qhash: type: string description: Secret of the release and delete links in the notification mails Fail2Ban: type: object properties: ban_time: type: integer description: Ban time in seconds ban_time_increment: type: boolean description: The ban time grows with every ban of a network max_ban_time: type: integer description: Maximum ban time in seconds netban_ipv4: type: integer description: IPv4 prefix length that is banned netban_ipv6: type: integer description: IPv6 prefix length that is banned max_attempts: type: integer description: Failed logins within `retry_window` that lead to a ban retry_window: type: integer description: Window in seconds for `max_attempts` banlist_id: type: string description: ID of the banlist URL `/f2b-banlist?id=` manage_external: type: integer description: 1 = netfilter sets no rules, the banlist is for an external firewall regex: type: object description: Regex filters by number additionalProperties: type: string whitelist: type: string description: Allowlisted networks and hosts, one per line blacklist: type: string description: Denylisted networks, one per line perm_bans: type: array description: Permanent bans (only present when there are any) items: type: object properties: network: type: string ip: type: string active_bans: type: array description: Active bans (only present when there are any) items: type: object properties: queued_for_unban: type: integer description: 1 when the ban is about to be lifted network: type: string ip: type: string banned_until: type: string description: Remaining ban time, e.g. `00h 27m 08s` Admin: type: object description: An administrator account properties: username: type: string tfa_active: type: integer enum: [0, 1] description: 1 = two-factor authentication is active tfa_active_int: type: integer enum: [0, 1] description: Same as `tfa_active` active: type: integer enum: [0, 1] description: 1 = the account can log in active_int: type: integer enum: [0, 1] description: Same as `active` created: type: string description: Creation time (`YYYY-MM-DD hh:mm:ss`) attributes: type: object properties: force_tfa: type: string enum: ["0", "1"] description: "\"1\" = two-factor authentication must be set up at the next login" force_pw_update: type: string enum: ["0", "1"] description: "\"1\" = the password must be changed at the next login" DomainAdmin: type: object description: A domain administrator account properties: username: type: string tfa_active: type: integer enum: [0, 1] description: 1 = two-factor authentication is active tfa_active_int: type: integer enum: [0, 1] description: Same as `tfa_active` active: type: integer enum: [0, 1] description: 1 = the account can log in active_int: type: integer enum: [0, 1] description: Same as `active` created: type: string description: Creation time (`YYYY-MM-DD hh:mm:ss`) attributes: type: object properties: force_tfa: type: string enum: ["0", "1"] description: "\"1\" = two-factor authentication must be set up at the next login" force_pw_update: type: string enum: ["0", "1"] description: "\"1\" = the password must be changed at the next login" selected_domains: type: array description: The domains the account administers items: type: string unselected_domains: description: All other domains, `""` if there are none oneOf: - type: array items: type: string - type: string const: "" DomainAdminAcl: type: string description: >- ACL of a domain administrator. New domain administrators get all except `pushover`, `extend_sender_acl` (sender ACL with external addresses), `unlimited_quota`, `alias_domains` and `domain_desc`. enum: - syncjobs - quarantine - login_as - sogo_access - app_passwds - bcc_maps - pushover - filters - ratelimit - spam_policy - extend_sender_acl - unlimited_quota - protocol_access - smtp_ip_access - alias_domains - mailbox_relayhost - domain_relayhost - domain_desc - alias_external_goto - mailbox_groups ApiKey: type: object description: An API key properties: id: type: integer description: type: string description: Free text; `API_KEY` or `API_KEY_READ_ONLY` for the service keys access: type: string enum: - ro - rw description: "`ro`: read-only (get routes only), `rw`: read/write" api_key: type: string description: The key value, sent in the `X-API-Key` header allow_from: type: array description: IP addresses and networks the key may be used from items: type: string skip_ip_check: type: integer enum: [0, 1] description: 1 = the key may be used from any address service: type: integer enum: [0, 1] description: 1 = service key from mailcow.conf, can only be changed there active: type: integer enum: [0, 1] created: type: [string, "null"] modified: type: [string, "null"] ApiKeyAttributes: type: object description: Attributes of an API key for add and edit properties: description: type: string description: Free text, at most 255 characters default: "" access: type: string enum: - ro - rw description: "`ro`: read-only (get routes only), `rw`: read/write. Required for a new key." allow_from: description: >- Allowed IP addresses and CIDR networks, as list or as string separated by spaces, commas, semicolons or newlines. An edit replaces the list. oneOf: - type: string - type: array items: type: string skip_ip_check: type: [integer, string, boolean] description: 1/true = allow the key from any address default: 0 active: type: [integer, string, boolean] description: 1/true = active default: 1 OAuth2Client: type: object description: An OAuth2 client of the mailcow OAuth2 server properties: id: type: integer description: ID used by the API client_id: type: string description: OAuth2 client ID client_secret: type: string description: OAuth2 client secret redirect_uri: type: string description: Redirect (callback) URL grant_types: type: [string, "null"] description: Not used scope: type: string description: Always `profile` user_id: type: [string, "null"] description: Not used SyslogLogEntry: type: object description: A log line of a container properties: time: type: string description: Unix time program: type: string description: Process that wrote the line priority: type: string description: Syslog priority (`info`, `warning`, `err`, ...) message: type: string AcmeLogEntry: type: object properties: time: type: string description: Unix time message: type: string ApiLogEntry: type: object properties: time: type: integer description: Unix time uri: type: string description: Request URI method: type: string description: HTTP method remote: type: string description: Client address data: type: string description: Form data of the request (`attr`, `items`), secrets replaced by `*` AutodiscoverLogEntry: type: object properties: time: type: integer description: Unix time ua: type: string description: User agent of the client user: type: string description: Requested e-mail address ip: type: string description: Client address service: type: string description: Offered service (`activesync`, `imap`) or an error CronLogEntry: type: object properties: time: type: integer description: Unix time priority: type: string task: type: string description: Name of the task message: type: string NetfilterLogEntry: type: object properties: time: type: integer description: Unix time priority: type: string description: "`info`, `warn` or `crit` (bans)" message: type: string RatelimitLogEntry: type: object properties: time: type: integer description: Unix time rcpt: type: string description: Recipients, comma separated from: type: string description: Envelope sender user: type: string description: Authenticated user rl_info: type: string description: Rate limit that was hit, `name(hash)` rl_name: type: string description: Name of the rate limit (mailbox or domain) rl_hash: type: string description: Hash of the rate limit bucket (see `delete/rlhash`) qid: type: string description: Postfix queue ID ip: type: string description: Client address message_id: type: string header_subject: type: string header_from: type: string RspamdHistoryEntry: type: object description: A message scanned by Rspamd (fields of Rspamd's history) properties: unix_time: type: integer time_real: type: number description: Scan time in seconds score: type: number required_score: type: number action: type: string description: "`no action`, `greylist`, `add header`, `rewrite subject`, `soft reject` or `reject`" thresholds: type: object additionalProperties: type: number ip: type: string user: type: string description: Authenticated user, `unknown` for incoming mail sender_smtp: type: string sender_mime: type: string rcpt_smtp: type: array items: type: string rcpt_mime: type: array items: type: string subject: type: string message-id: type: string size: type: integer is_skipped: type: boolean symbols: type: object description: Matched symbols by name additionalProperties: type: object properties: name: type: string score: type: number metric_score: type: number description: type: string options: type: array items: type: string additionalProperties: true RspamdStats: type: object description: Statistics of Rspamd's controller (`/stat`) properties: version: type: string config_id: type: string uptime: type: integer description: Seconds read_only: type: boolean scanned: type: integer learned: type: integer actions: type: object description: Number of messages per action additionalProperties: type: integer scan_times: type: array items: type: [number, "null"] spam_count: type: integer ham_count: type: integer connections: type: integer control_connections: type: integer total_learns: type: integer statfiles: type: array description: Bayes statistics items: type: object fuzzy_hashes: type: object additionalProperties: type: integer additionalProperties: true SaslLogEntry: type: object properties: service: type: string description: "`imap`, `pop3`, `smtp`, `sieve`, `SSO` (SOGo), ..." app_password: type: integer description: ID of the app password used, 0 = the mailbox password username: type: string real_rip: type: string description: Client address datetime: type: string description: Time of the last login (`YYYY-MM-DD hh:mm:ss`) UiLogEntry: type: object properties: id: type: integer task: type: string description: ID of the request type: type: string description: "`success`, `danger`, `warning` or `info`" msg: type: string description: The message (JSON) call: type: string description: The call that produced it (JSON) user: type: string description: Account (`API` for API keys) role: type: string remote: type: string description: Client address time: type: integer description: Unix time WatchdogLogEntry: type: object properties: time: type: string description: Unix time service: type: string description: Checked service lvl: type: string description: Health in percent hpnow: type: string description: Current health points hptotal: type: string description: Maximum health points hpdiff: type: string description: Change since the last check ContainerStatus: type: object properties: type: type: string const: info container: type: string description: Service name state: type: string description: Docker state (`running`, `exited`, `restarting`, ...) started_at: type: string description: Start time (RFC 3339) image: type: string HostStats: type: object properties: cpu: type: object properties: cores: type: integer usage: type: number description: CPU usage in percent memory: type: object properties: total: type: integer description: Bytes usage: type: number description: Memory usage in percent swap: type: array description: Swap total, used, free (bytes), used percent, swapped in, swapped out (bytes) items: type: number uptime: type: number description: Seconds since boot system_time: type: string description: Host time (`DD.MM.YYYY hh:mm:ss`) architecture: type: string PasswordPolicy: type: object description: Password policy; the values are strings, `false` if never saved properties: length: type: [string, boolean] description: Minimum length chars: type: [string, boolean] description: "\"1\": at least one letter" special_chars: type: [string, boolean] description: "\"1\": at least one character that is no letter or digit" lowerupper: type: [string, boolean] description: "\"1\": lowercase and uppercase letters" numbers: type: [string, boolean] description: "\"1\": at least one digit" MailboxGroupAttributes: type: object description: >- Attributes of a mailbox group. Flags take `1`, `true`, `on` or `yes` for on, anything else is off. Lists take a JSON array or a string separated by spaces, commas, semicolons or newlines; entries are lowercased. properties: name: type: string description: 1-100 characters, unique in the domain description: type: string description: Max. 255 characters default: "" address: type: string description: >- Distribution address in the domain of the group, not used by a mailbox or alias yet; empty = none. Wins over `local_part`. local_part: type: string description: Local part of the address in the domain of the group; empty = no address members: type: - array - string items: type: string description: Regular mailboxes; replaces the manual members the caller may access add_members: type: - array - string items: type: string description: Mailboxes to add remove_members: type: - array - string items: type: string description: Manual members to remove send_as: type: - array - string items: type: string description: >- Replaces the addresses the members may send as: mailbox or alias addresses or `@domain`; for the group address use `sender_allowed` sender_allowed: type: - boolean - integer - string description: Members may send as the group address default: 0 sogo_visible: type: - boolean - integer - string description: Offer the group address as identity in SOGo (only with `sender_allowed`) default: 0 internal: type: - boolean - integer - string description: Only senders of the domain may write to the group address default: 0 active: type: - boolean - integer - string default: 1 imap_grants: description: >- Replaces the mailboxes the members may open as Shared/; the caller needs access to every owner. `subscribe` subscribes the folders for every member once, within 15 minutes. JSON text is accepted too. type: - array - string items: type: object required: - owner properties: owner: type: string description: Mailbox to share rights: type: string description: >- read = lookup, read, write-seen; write = also write, write-deleted, insert, post, expunge, create; full = also delete enum: - read - write - full default: read subscribe: type: - boolean - integer - string default: 0 sogo_grants: description: >- Replaces the SOGo folders shared with the members; the caller needs access to every owner. Pending until the owner has opened SOGo once. `subscribe` subscribes every member once. JSON text is accepted too. type: - array - string items: type: object required: - owner properties: owner: type: string description: Mailbox whose folder is shared type: type: string enum: - Calendar - Contacts default: Calendar folder: type: string description: SOGo folder id (`A-Za-z0-9._-`, max. 100 characters) default: personal access: type: string enum: - read - write default: read subscribe: type: - boolean - integer - string default: 0 template_id: type: - integer - string - "null" description: >- Admins only: id of a mailbox template applied to the members; null, empty or 0 = none priority: type: - integer - string description: >- Admins only: -1000000 to 1000000; of several groups with a template the one with the highest priority wins default: 0 idp_ref: type: string description: >- Admins only: Identity Provider group id to sync the members from (max. 255 characters); empty = none MailboxGroup: type: object properties: id: type: integer domain: type: string name: type: string description: type: string address: type: - string - "null" description: Distribution address, null = none sender_allowed: type: integer enum: - 0 - 1 sogo_visible: type: integer enum: - 0 - 1 internal: type: integer enum: - 0 - 1 template_id: type: - integer - "null" template: type: - string - "null" description: Name of the template priority: type: integer idp_ref: type: - string - "null" description: Identity Provider group id, set = members are synced members: type: array items: type: object properties: username: type: string source: type: string description: manual = added in mailcow, idp = added by the identity sync enum: - manual - idp send_as: type: array description: Addresses and `@domain` entries the members may send as items: type: string imap_grants: type: array items: type: object properties: owner: type: string rights: type: string enum: - read - write - full subscribe: type: integer enum: - 0 - 1 state: type: string description: failed = setting the ACL failed, retried later enum: - pending - applied - failed last_error: type: - string - "null" sogo_grants: type: array items: type: object properties: owner: type: string type: type: string enum: - Calendar - Contacts folder: type: string access: type: string enum: - read - write subscribe: type: integer enum: - 0 - 1 state: type: string description: pending (`last_error` folder_missing) until the SOGo folder of the owner exists enum: - pending - applied - failed last_error: type: - string - "null" active: type: integer enum: - 0 - 1 created: type: - string - "null" modified: type: - string - "null" can_edit: type: boolean description: The caller may change the group (false for read-only API keys) MailboxGroupMemberships: type: object properties: groups: type: array items: type: object properties: id: type: integer domain: type: string name: type: string address: type: - string - "null" sender_allowed: type: integer active: type: integer priority: type: integer template: type: - string - "null" source: type: string enum: - manual - idp template: type: - string - "null" description: Effective group template of the mailbox send_as: type: array description: Addresses the mailbox may send as through its active groups items: type: string SyncJobAttributes: type: object description: >- Attributes of a sync job. Flags are cast to integers: `1`, `"1"` and `true` are on; `0`, `"0"`, `false` and the string `"true"` are off. Flags not sent on add are off. `host1`, `port1`, `enc1` and `authmech1` are ignored, the connection comes from `source_id`. properties: source_id: type: - integer - string description: >- Id of an active sync source the caller may see (`GET /api/v1/get/syncjob_source/all`) user1: type: string description: Remote username at the source, max. 255 characters password1: type: string format: password description: >- Remote password; required unless the source uses XOAUTH2 (ignored then); empty on edit = keep mins_interval: type: - integer - string description: Minutes between runs, 1-43800 subfolder2: type: string description: Folder in the local mailbox to sync into, empty = none default: "" exclude: type: string description: Regular expression of remote folders to skip default: "" maxage: type: - integer - string description: Only sync messages up to this age in days (1-32000), 0 = all default: 0 maxbytespersecond: type: - integer - string description: >- Bandwidth limit in bytes/s (1-125000000), 0 = unlimited; the global limit of `edit/imapsync_settings` caps it default: 0 timeout1: type: - integer - string description: Timeout of the remote connection in seconds (1-32000) default: 600 timeout2: type: - integer - string description: Timeout of the local connection in seconds (1-32000) default: 600 custom_params: type: array description: >- Extra imapsync options allowed by `GET /api/v1/get/syncjob_options`; replaces the stored list, empty or null = none. Max. 100 options, values max. 1000 characters, each value is one argument. items: $ref: "#/components/schemas/SyncJobCustomParam" delete2duplicates: type: - integer - string - boolean description: Delete duplicates in the local mailbox (--delete2duplicates) delete1: type: - integer - string - boolean description: Delete messages at the source after they were synced (--delete1) delete2: type: - integer - string - boolean description: Delete local messages that are not at the source (--delete2) automap: type: - integer - string - boolean description: Map special folders like "Sent Items" to their local counterparts (--automap) skipcrossduplicates: type: - integer - string - boolean description: Skip duplicates across folders, first come first served (--skipcrossduplicates) subscribeall: type: - integer - string - boolean description: Subscribe all folders (--subscribeall) dry: type: - integer - string - boolean description: Dry run, change nothing (--dry) active: type: - integer - string - boolean description: The job runs; a new job without `active` is inactive default: 0 SyncJobCustomParam: type: object required: - o properties: o: type: string description: Option name, case-insensitive, leading dashes are removed example: folder v: type: string description: Value, empty for flags default: "" example: INBOX SyncJob: type: object description: A sync job; the remote password is never returned. properties: id: type: integer user2: type: string description: Local mailbox user1: type: string description: Remote username source_id: type: integer subfolder2: type: string exclude: type: string maxage: type: integer mins_interval: type: integer maxbytespersecond: type: string description: Bytes/s as text, "0" = unlimited timeout1: type: integer timeout2: type: integer custom_params: type: - string - "null" description: 'JSON text of the option list, e.g. `[{"o":"folder","v":"INBOX"}]`' custom_params_legacy: type: - string - "null" description: Free-text options of jobs from before the allowlist, not used by the runner delete2duplicates: type: integer delete1: type: integer delete2: type: integer automap: type: integer skipcrossduplicates: type: integer subscribeall: type: integer dry: type: integer active: type: integer regextrans2: type: - string - "null" description: Legacy column, read-only authmd51: type: integer description: Legacy column, read-only domain2: type: string description: Legacy column, read-only is_running: type: integer last_run: type: - string - "null" success: type: - integer - "null" description: Result of the last run (1 = imapsync exited with 0), null = not run yet exit_status: type: - string - "null" description: Exit status name of imapsync, e.g. EX_OK prio: type: integer description: Queue priority, higher runs first created: type: - string - "null" modified: type: - string - "null" source_name: type: - string - "null" source_description: type: - string - "null" source_host: type: - string - "null" source_port: type: - integer - "null" source_enc: type: - string - "null" source_auth_type: type: - string - "null" source_created_by: type: - string - "null" source_scope: type: - string - "null" source_oauth_flow: type: - string - "null" source_active: type: - integer - "null" source_oauth_token_expires: type: - integer - "null" description: Expiry (Unix time) of the token of a client_credentials source source_oauth_last_refresh_error: type: - string - "null" user_token_expires: type: - integer - "null" description: Expiry (Unix time) of the sign-in token of an authorization_code source user_token_error: type: - string - "null" user_token_exists: type: integer description: 1 = a sign-in token exists for (source, local mailbox, user1) log: type: string description: Output of the last run; empty with `no_log` SyncJobSourceAttributes: type: object description: >- Attributes of a sync source; on edit, attributes that are not sent keep their value. properties: name: type: string description: 1-100 characters, unique per creator description: type: string description: Max. 255 characters default: "" host: type: string description: IMAP server, host name or IP address (`host1` is accepted too) port: type: - integer - string description: 1-65535 (`port1` is accepted too) enc: type: string description: TLS = STARTTLS (`enc1` is accepted too) enum: - TLS - SSL - PLAIN default: TLS verify_cert: type: - integer - string - boolean description: Verify the server certificate; `0`, `"0"`, `false` or empty = no default: 1 auth_type: type: string description: >- PLAIN, LOGIN and CRAM-MD5 use the password of each job, XOAUTH2 an OAuth2 token. Users cannot create or edit XOAUTH2 sources, but may use the ones they see. enum: - PLAIN - LOGIN - CRAM-MD5 - XOAUTH2 default: PLAIN active: type: - integer - string description: 1 = usable for jobs (cast to integer) default: 1 scope: type: string description: >- Who may use the source: `all` (admins only), `domain` (the `domains`), `user` (the `users`; none = only the creator). Sources of users and client_credentials sources are always `user` without targets. On edit the targets only change when `scope` is sent. enum: - all - domain - user default: user domains: type: array description: Domains for scope `domain` (at least one), the caller must manage them items: type: string users: type: array description: Mailboxes for scope `user`, the caller must have access to them items: type: string oauth_flow: type: string description: >- XOAUTH2 grant: client_credentials = one token of the source for all mailboxes of the tenant; authorization_code = every mailbox owner signs in once in the mailcow UI (redirect URI `https:///syncjob-oauth`) enum: - client_credentials - authorization_code default: client_credentials oauth_token_endpoint: type: string description: XOAUTH2, required; https:// URL oauth_authorize_endpoint: type: string description: XOAUTH2 authorization_code, required; https:// URL oauth_userinfo_endpoint: type: string description: >- XOAUTH2 authorization_code, optional: identity endpoint used when the token response has no usable id_token; https:// URL oauth_client_id: type: string description: XOAUTH2, required, max. 500 characters oauth_client_secret: type: string format: password description: >- XOAUTH2, required, max. 500 characters; empty on edit = keep. Never returned. oauth_scope: type: string description: XOAUTH2, required, max. 500 characters oauth_extra_params: description: >- XOAUTH2, optional: extra OAuth2 parameters as JSON object or JSON text (max. 4000 characters). `prompt`, `access_type`, `login_hint`, `domain_hint` and `hd` go to the sign-in URL, others to the token request; standard fields cannot be overridden. type: - object - string - "null" additionalProperties: type: - string - number - boolean - "null" SyncJobSource: type: object description: A sync source; secrets are never returned. properties: id: type: integer name: type: string description: type: string created_by: type: string description: Creator; `API` for API keys, empty = handed over to the admins (creator deleted) scope: type: string enum: - all - domain - user domains: type: array items: type: string users: type: array items: type: string host: type: string port: type: integer enc: type: - string - "null" host1: type: string description: Same as `host` port1: type: integer description: Same as `port` enc1: type: - string - "null" description: Same as `enc` verify_cert: type: integer auth_type: type: - string - "null" active: type: integer oauth_flow: type: string oauth_token_endpoint: type: - string - "null" oauth_authorize_endpoint: type: - string - "null" oauth_userinfo_endpoint: type: - string - "null" oauth_client_id: type: - string - "null" oauth_scope: type: - string - "null" oauth_extra_params: type: - string - "null" description: JSON text, null for callers who may not edit the source oauth_token_expires: type: - integer - "null" description: Expiry (Unix time) of the token of a client_credentials source oauth_last_refresh_error: type: - string - "null" oauth_last_refresh_attempt: type: - string - "null" oauth_redirect_uri: type: string description: Only for authorization_code sources, register it at the provider has_client_secret: type: boolean has_access_token: type: boolean can_edit: type: boolean description: The caller may change the source (false for read-only API keys) created: type: - string - "null" modified: type: - string - "null" SyncJobSettings: type: object properties: max_parallel: type: integer description: Sync jobs running at the same time max_bytes_per_second: type: integer description: Bandwidth limit per sync job process in bytes/s, 0 = unlimited max_kb_per_second: type: integer description: The same in KB/s IdentityProviderAttributes: type: object required: - authsource description: >- Configuration of the Identity Provider. Flags marked (boolean) are on for any non-empty value except `0`/`"0"`/`false`; flags marked (0/1) are cast to integers (the string `"true"` is 0). properties: authsource: type: string description: Provider type (case-insensitive) enum: - keycloak - generic-oidc - ldap client_id: type: string description: Keycloak, generic-oidc client_secret: type: string format: password description: Keycloak, generic-oidc redirect_url: type: string description: Keycloak, generic-oidc; URL of mailcow the provider redirects to after the login redirect_url_extra: type: - array - string items: type: string description: Keycloak, generic-oidc; more allowed redirect URLs, only changed when sent server_url: type: string description: Keycloak base URL realm: type: string description: Keycloak realm version: type: string description: Keycloak version mailpassword_flow: type: - integer - string - boolean description: (0/1) Keycloak; check mail client passwords through the Keycloak admin API default: 0 group_paths: type: string description: >- Keycloak group sync: comma-separated group paths, e.g. `/Sales` or `/mailcow/*` (all groups below /mailcow); needs the `query-groups` permission default: "" authorize_url: type: string description: generic-oidc authorization endpoint token_url: type: string description: generic-oidc token endpoint userinfo_url: type: string description: generic-oidc userinfo endpoint client_scopes: type: string description: generic-oidc scopes default: openid profile email mailcow_template host: type: string description: LDAP server, several separated by commas (spaces are removed) default: "" port: type: - integer - string description: LDAP port default: 389 use_ssl: type: - boolean - integer - string description: (boolean) LDAP over SSL default: false use_tls: type: - boolean - integer - string description: (boolean) LDAP StartTLS, ignored with `use_ssl` default: false basedn: type: string description: LDAP base DN of the user search binddn: type: string description: LDAP bind DN bindpass: type: string format: password description: LDAP bind password username_field: type: string description: LDAP attribute with the mail address of the user default: mail filter: type: string description: LDAP filter of the users that may log in default: "" attribute_field: type: string description: LDAP attribute whose value is matched against `mappers` default: "" id_attribute: type: string description: >- LDAP attribute with a stable user id; empty = objectGUID, entryUUID, nsUniqueId or ipaUniqueID, else the DN default: "" disabled_filter: type: string description: >- LDAP filter of disabled users (Active Directory accounts with ACCOUNTDISABLE are always disabled) default: "" group_basedn: type: string description: LDAP base DN of the group search, empty = `basedn` default: "" group_filter: type: string description: LDAP filter of the synced groups, required for the group sync default: "" group_name_attribute: type: string default: cn group_member_mode: type: string description: >- LDAP source of the memberships: memberOf of the users, member attribute of the groups, or Active Directory incl. nested groups enum: - memberof - member - ad_chain default: memberof group_member_attribute: type: string description: LDAP member attribute for `group_member_mode` member default: member ignore_ssl_error: type: - boolean - integer - string description: (boolean) Do not verify TLS certificates default: false login_provisioning: type: - boolean - integer - string description: (boolean) Create mailboxes at their first login default: false periodic_sync: type: - integer - string - boolean description: (0/1) Keycloak, LDAP; update mailboxes from the provider every `sync_interval` default: 0 import_users: type: - integer - string - boolean description: (0/1) Keycloak, LDAP; create mailboxes for new users of the provider default: 0 sync_interval: type: - integer - string description: Keycloak, LDAP; minutes between sync runs (at least 1) default: 15 offboarding: type: - integer - string - boolean description: >- (0/1) Keycloak, LDAP; disable the login (mail still arrives) of users disabled at the provider or missing in two complete runs; the sync enables only mailboxes it disabled default: 0 offboarding_limit: type: - integer - string description: >- Keycloak, LDAP; runs that would disable more mailboxes or remove more group memberships than this share in percent (0-100, at least 5 mailboxes) are blocked default: 10 group_sync: type: - integer - string - boolean description: >- (0/1) Keycloak, LDAP; sync the members of provider groups to mailbox groups (members added in mailcow stay) default: 0 group_autocreate: type: - integer - string - boolean description: >- (0/1) Keycloak, LDAP; create a mailbox group for every provider group without one default: 0 group_default_domain: type: string description: Keycloak, LDAP; domain of new groups whose mail is not in a mailcow domain default: "" default_template: type: string description: >- Mailbox template for new mailboxes without a matching mapping (not used for updates); only changed when sent mappers: type: array items: type: string description: >- Attribute values, each mapped to the template at the same position in `templates`; only changed when both lists are sent, pairs with an empty value are dropped templates: type: array items: type: string description: Mailbox templates for `mappers` IdentityProviderSettings: type: object description: >- Stored settings (see `IdentityProviderAttributes`), mostly as strings. Secrets are `*` for read-only API keys. properties: authsource: type: string client_secret: type: string bindpass: type: string access_token: type: string description: Cached admin API token of Keycloak redirect_url_extra: type: array items: type: string mappers: type: array items: type: string templates: type: array items: type: string use_ssl: type: boolean use_tls: type: boolean ignore_ssl_error: type: boolean login_provisioning: type: - boolean - integer additionalProperties: type: string IdentitySyncStatus: type: object properties: provider: type: string description: Configured provider, empty = none can_sync: type: boolean description: The provider can be synced (Keycloak, LDAP) sync_enabled: type: boolean description: Scheduled runs are on (periodic sync, import, offboarding or group sync) counts: type: object description: Mailboxes of the provider (no resources) properties: accounts: type: integer linked: type: integer description: Linked to a user of the provider idp_disabled: type: integer description: Login disabled by the sync missing: type: integer description: Not found at the provider by the last runs runs: type: array description: The last 10 runs, newest first items: $ref: "#/components/schemas/IdentitySyncRun" IdentitySyncRun: type: object properties: id: type: integer provider: type: string mode: type: string enum: - run - preview - force status: type: string enum: - pending - running - ok - blocked - error requested_by: type: string description: Who requested the run, empty for scheduled runs created: type: string started: type: - string - "null" finished: type: - string - "null" summary: type: - object - "null" description: >- Result, null while pending: `counts` per kind of change, `details` (up to 50 entries per list), `blocked`, `errors` (up to 50), `mode`; failed runs only `error` and `mode` properties: counts: type: object additionalProperties: type: integer details: type: object additionalProperties: type: array items: type: string blocked: type: boolean errors: type: array items: type: string error: type: string mode: type: string IdentityLink: type: object properties: provider: type: string external_id: type: - string - "null" description: User id at the provider idp_disabled: type: integer description: 1 = login disabled by the identity sync missing_since: type: - string - "null" description: Since when the sync does not find the user at the provider responses: Unauthorized: description: >- The API key is unknown or inactive (`authentication failed`), or the request comes from an address the key does not allow (`api access denied for ip
`) content: application/json: schema: $ref: "#/components/schemas/Error" example: type: error msg: authentication failed Forbidden: description: The API key is read-only content: application/json: schema: $ref: "#/components/schemas/Error" example: type: error msg: API read/write access denied WriteResult: description: >- The messages of the call; `{"type": "success", "msg": "Task completed"}` or `{"type": "error", "msg": "Cannot ... item"}` if it produced none. Check `type`: the status is 200 for failures too. content: application/json: schema: oneOf: - $ref: "#/components/schemas/Messages" - $ref: "#/components/schemas/TaskResult" examples: messages: summary: Messages of the call value: - type: success log: - mailbox - add - alias - address: alias@example.org goto: user@example.org msg: - alias_added - alias@example.org failed: summary: Failed without a message value: type: error msg: Cannot add item AcmeLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/AcmeLogEntry" example: - time: "1794308452" message: mail.example.org - Certificates were successfully validated, no changes or renewals required, sleeping for another day. ApiLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/ApiLogEntry" example: - time: 1794334338 uri: /api/v1/edit/domain-admin method: POST remote: 192.0.2.10 data: "attr='{\"active\":\"1\",\"password\":\"*\",\"password2\":\"*\"}', items='[\"domainadmin1\"]'" - time: 1794334330 uri: /api/v1/get/status/version method: GET remote: 192.0.2.10 data: "" AutodiscoverLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/AutodiscoverLogEntry" example: - time: 1794311051 ua: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.17928; Pro) user: john.doe@example.org ip: 198.51.100.7 service: activesync CronLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/CronLogEntry" example: - time: 1794096901 priority: warning task: Group Shares message: "group_imap_grant_failed: info@example.org" DovecotLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/SyslogLogEntry" example: - time: "1794334332" program: dovecot priority: info message: "imap-login: Login: user=, method=PLAIN, rip=198.51.100.7, lip=172.22.1.250, mpid=310, TLS, session=" NetfilterLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/NetfilterLogEntry" example: - time: 1794334242 priority: crit message: Banning 203.0.113.5/32 for 30 minutes - time: 1794334242 priority: warn message: "203.0.113.5 matched rule id 3 (warning: unknown[203.0.113.5]: SASL LOGIN authentication failed: ...)" PostfixLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/SyslogLogEntry" example: - time: "1794334301" program: postfix/smtpd priority: info message: "connect from mail.example.com[198.51.100.20]" RatelimitLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/RatelimitLogEntry" example: - time: 1794334001 rcpt: jane@example.com from: john.doe@example.org user: john.doe@example.org rl_info: john.doe@example.org(RLsdz3tuabozgd4oacbdh8kc78) rl_name: john.doe@example.org rl_hash: RLsdz3tuabozgd4oacbdh8kc78 qid: E3CF91500458 ip: 172.22.1.248 message_id: 6a-5d892500-7-240abd80@example.org header_subject: Newsletter header_from: "\"John Doe\" " RspamdHistory: description: The scanned messages, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/RspamdHistoryEntry" example: - unix_time: 1794333685 time_real: 0.510136 score: -1.229459 required_score: 15 action: no action thresholds: reject: 15 add header: 8 greylist: 7 ip: 198.51.100.20 user: unknown sender_smtp: jane@example.com sender_mime: jane@example.com rcpt_smtp: - john.doe@example.org rcpt_mime: - john.doe@example.org subject: Meeting tomorrow message-id: 20261110190100.428319@mail.example.com size: 1015 is_skipped: false symbols: DMARC_POLICY_ALLOW: name: DMARC_POLICY_ALLOW score: -0.5 metric_score: -0.5 description: DMARC permit policy options: - example.com - none SaslLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/SaslLogEntry" example: - service: imap app_password: 0 username: john.doe@example.org real_rip: 198.51.100.7 datetime: "2026-11-10 19:07:01" SogoLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/SyslogLogEntry" example: - time: "1794334303" program: sogod priority: notice message: "[52]: 198.51.100.7 \"GET /SOGo/so/john.doe@example.org/Mail/view HTTP/1.1\" 200 2578/0 0.002 - - 0 - 12" UiLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/UiLogEntry" example: - id: 1819 task: 97D254 type: success msg: "[\"domain_admin_modified\",\"domainadmin1\"]" call: "[\"domain_admin\",\"edit\",{\"username\":[\"domainadmin1\"],\"active\":\"1\"}]" user: API role: admin remote: 192.0.2.10 time: 1794319670 WatchdogLogs: description: The log entries, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/WatchdogLogEntry" example: - time: "1794334334" service: Dovecot lvl: "100" hpnow: "12" hptotal: "12" hpdiff: "0" parameters: MailboxTagsQuery: name: tags in: query required: false description: "Comma-separated tags: only mailboxes with a tag containing one of them" schema: type: string example: sales,support examples: MailboxDetails: summary: A mailbox value: username: john.doe@example.org active: 1 active_int: 1 domain: example.org name: John Doe local_part: john.doe quota: 3221225472 messages: 1207 attributes: force_pw_update: "0" force_tfa: "0" tls_enforce_in: "0" tls_enforce_out: "0" sogo_access: "1" imap_access: "1" pop3_access: "0" smtp_access: "1" sieve_access: "1" eas_access: "1" dav_access: "1" relayhost: "0" shared: "0" passwd_update: "2026-11-03 09:37:37" mailbox_format: "maildir:" quarantine_notification: hourly quarantine_category: reject attribute_hash: "" recovery_email: "" custom_attributes: department: Sales quota_used: 418219315 percent_in_use: 13 created: "2026-11-03 09:37:37" modified: "2026-11-06 20:20:46" authsource: mailcow percent_class: success last_imap_login: 1794052021 last_smtp_login: 1793788402 last_pop3_login: 0 last_sso_login: 1794005152 last_sogo_login: 1794005160 max_new_quota: 10737418240 spam_aliases: 1 pushover_active: 0 rl: value: "100" frame: h rl_scope: mailbox is_relayed: 0 sender_acl: - sales@example.org tags: - sales MailboxList: summary: Mailboxes value: - username: john.doe@example.org active: 1 active_int: 1 domain: example.org name: John Doe local_part: john.doe quota: 3221225472 messages: 1207 attributes: force_pw_update: "0" force_tfa: "0" tls_enforce_in: "0" tls_enforce_out: "0" sogo_access: "1" imap_access: "1" pop3_access: "0" smtp_access: "1" sieve_access: "1" eas_access: "1" dav_access: "1" relayhost: "0" shared: "0" passwd_update: "2026-11-03 09:37:37" mailbox_format: "maildir:" quarantine_notification: hourly quarantine_category: reject attribute_hash: "" custom_attributes: [] quota_used: 418219315 percent_in_use: 13 created: "2026-11-03 09:37:37" modified: "2026-11-06 20:20:46" authsource: mailcow percent_class: success last_imap_login: 1794052021 last_smtp_login: 1793788402 last_pop3_login: 0 last_sso_login: 0 last_sogo_login: 1794005160 max_new_quota: 10737418240 spam_aliases: 0 pushover_active: 0 rl: false rl_scope: domain is_relayed: 0 sender_acl: [] MailboxSearchPage: summary: One page of mailboxes value: draw: 1 recordsTotal: 1 recordsFiltered: 1 data: - username: john.doe@example.org active: 1 active_int: 1 domain: example.org name: John Doe local_part: john.doe quota: 3221225472 messages: 1207 attributes: force_pw_update: "0" force_tfa: "0" tls_enforce_in: "0" tls_enforce_out: "0" sogo_access: "1" imap_access: "1" pop3_access: "0" smtp_access: "1" sieve_access: "1" eas_access: "1" dav_access: "1" relayhost: "0" shared: "0" passwd_update: "2026-11-03 09:37:37" mailbox_format: "maildir:" quarantine_notification: hourly quarantine_category: reject attribute_hash: "" custom_attributes: [] quota_used: 418219315 percent_in_use: 13 created: "2026-11-03 09:37:37" modified: "2026-11-06 20:20:46" authsource: mailcow percent_class: success last_imap_login: 1794052021 last_smtp_login: 1793788402 last_pop3_login: 0 last_sso_login: 0 last_sogo_login: 1794005160 max_new_quota: 10737418240 spam_aliases: 0 pushover_active: 0 rl: false rl_scope: domain is_relayed: 0 sender_acl: [] tags: - sales security: - ApiKeyAuth: [] paths: /api/v1/add/alias: post: tags: - Aliases summary: Create aliases operationId: addAlias description: >- Creates an alias for every address in `address`, all with the same destinations; domain administrators for their domains. Flags not sent are 0: send `active`, `sogo_visible` and `sender_allowed` as 1 to get an alias like the UI creates it. Messages: `alias_added`; errors `is_alias_or_mailbox`, `goto_invalid`, `external_goto_denied`, `max_alias_exceeded`. requestBody: content: application/json: schema: type: object properties: address: type: string description: >- Alias addresses of mailcow domains or alias domains, separated by spaces, commas, semicolons or line breaks; `@example.org` is a catch-all goto: type: string description: >- Destination addresses, separated by spaces, commas, semicolons or line breaks; required unless a `goto_*` flag is 1 goto_null: type: [boolean, integer, string] description: 1 = discard the mail silently; wins over `goto_spam` and `goto_ham` default: 0 goto_spam: type: [boolean, integer, string] description: 1 = learn the mail as spam; wins over `goto_ham` default: 0 goto_ham: type: [boolean, integer, string] description: 1 = learn the mail as ham default: 0 active: type: [boolean, integer, string] description: 1 = active, 0 = inactive default: 0 sogo_visible: type: [boolean, integer, string] description: 1 = selectable sender in SOGo (aliases with a local mailbox as destination) default: 0 internal: type: [boolean, integer, string] description: 1 = only reachable from its own domain and its alias domains default: 0 sender_allowed: type: [boolean, integer, string] description: 1 = the destination mailboxes may send as this alias default: 0 public_comment: type: string description: Comment shown to the users maxLength: 160 private_comment: type: string description: Comment for administrators maxLength: 160 required: - address example: address: sales@example.org goto: anna@example.org,ben@example.org active: "1" sogo_visible: "1" sender_allowed: "1" internal: "0" public_comment: Sales team responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/time_limited_alias: post: tags: - Mailbox user settings summary: Create a time-limited alias operationId: addTimeLimitedAlias description: >- Creates a random alias that delivers to the mailbox until it expires. Needs the user ACL `spam_alias`. `domain` must be the domain of the mailbox or one of its alias domains. Messages: `mailbox_modified`; errors `domain_invalid`, `validity_missing`. requestBody: required: true content: application/json: schema: type: object required: - domain properties: username: type: string description: Mailbox the alias delivers to (required for API keys) domain: type: string description: Domain of the alias description: type: string default: "" description: Note for the alias validity: type: [integer, string] minimum: 1 maximum: 87600 default: 8760 description: Hours until the alias expires permanent: type: [boolean, integer, string] default: false description: true keeps the alias after it expired example: username: john.doe@example.org domain: example.org description: Online shop registration validity: 720 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/api-key: post: summary: Create API key description: >- Creates an API key with a random value; read the value with `get/api-key/all`. Without `skip_ip_check`, `allow_from` is required. Messages: `api_key_added`; errors `api_key_access_invalid`, `api_key_network_invalid`, `ip_list_empty`. operationId: addApiKey tags: - API Keys requestBody: required: true content: application/json: schema: allOf: - $ref: "#/components/schemas/ApiKeyAttributes" - required: - access example: description: provisioning access: rw allow_from: "192.0.2.10, 2001:db8::/64" skip_ip_check: 0 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/app-passwd: post: tags: - App Passwords summary: Create an app password operationId: addAppPassword description: >- Adds an app password to a mailbox, valid only for the listed protocols. Needs the user ACL `app_passwds`. Messages: `app_passwd_added`; errors `password_complexity`, `password_mismatch`, `app_name_empty`. requestBody: required: true content: application/json: schema: type: object required: - app_name - app_passwd - app_passwd2 properties: username: type: string description: Mailbox the app password belongs to (required for API keys) app_name: type: string description: Name of the app password app_passwd: type: string format: password description: The password, checked against the password policy app_passwd2: type: string format: password description: The password again protocols: description: Protocols the password is valid for; not listed = not allowed type: array items: type: string enum: - imap_access - smtp_access - pop3_access - sieve_access - dav_access - eas_access active: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: 1 active, 0 inactive example: username: john.doe@example.org app_name: Thunderbird app_passwd: eiQu4ahz8iePh app_passwd2: eiQu4ahz8iePh protocols: - imap_access - smtp_access - sieve_access active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/bcc: post: tags: - Address Rewriting summary: Create a BCC map operationId: addBccMap description: >- Sends a hidden copy of the mail of a domain or address to `bcc_dest`. Domain administrators need the BCC maps ACL. Undeliverable copies are not reported to the local destination. Messages: `bcc_saved`; errors `bcc_must_be_email`, `bcc_exists`. requestBody: content: application/json: schema: type: object properties: local_dest: type: string description: A mailcow domain or the address of a mailbox or alias bcc_dest: type: string description: One e-mail address that gets the copies (use an alias for several) type: type: string enum: - sender - rcpt description: >- `sender`: copy the mail sent by `local_dest`; `rcpt`: copy the mail sent to it active: type: [boolean, integer, string] description: 1 = active, 0 = inactive default: 0 required: - local_dest - bcc_dest - type example: local_dest: example.org bcc_dest: archive@example.com type: rcpt active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/dkim: post: summary: Generate DKIM keys description: >- Generates an RSA DKIM key for each domain or alias domain; existing keys are kept. Messages: `dkim_added`; error `dkim_domain_or_sel_invalid`. operationId: addDkimKey tags: - DKIM requestBody: required: true content: application/json: schema: type: object required: - domains - key_size properties: domains: type: string description: >- Domain names, separated by spaces, commas, semicolons or line breaks dkim_selector: type: string default: dkim description: Selector (letters, digits, `-`, `_`, `.`) key_size: type: [integer, string] description: RSA key size in bits example: domains: example.org, example.net dkim_selector: dkim key_size: 2048 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/dkim_duplicate: post: summary: Copy a DKIM key to other domains description: >- Copies the DKIM key and selector of `from_domain` to the `to_domain` domains, replacing their keys. Target names are not checked. Messages: `dkim_duplicated`; error `dkim_domain_or_sel_invalid`. operationId: duplicateDkimKey tags: - DKIM requestBody: required: true content: application/json: schema: type: object required: - from_domain - to_domain properties: from_domain: type: string description: Domain whose key is copied to_domain: description: Domain name or list of domain names that get the key oneOf: - type: string - type: array items: type: string example: from_domain: example.org to_domain: - example.net - example.com responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/domain: post: summary: Add a domain description: >- Adds a domain. Quotas are in MiB. Fields not sent come from the domain template in `template` (default: `Default`). Also sets the rate limit and creates a DKIM key. SOGo sees the new domain only after a restart (`restart_sogo`). Messages: `domain_added`, `dkim_added`, `rl_saved`; errors `domain_invalid`, `domain_exists`, `maxquota_empty`. operationId: addDomain tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - domain properties: domain: type: string description: Domain name (stored lowercase, IDN as punycode) description: type: string description: Description, default the domain name template: type: [integer, string] description: ID of the domain template for fields not sent aliases: type: [integer, string] description: Max. number of aliases mailboxes: type: [integer, string] description: Max. number of mailboxes defquota: type: [integer, string] description: Default quota of new mailboxes in MiB, must not be 0 maxquota: type: [integer, string] description: Max. quota per mailbox in MiB, must not be 0 quota: type: [integer, string] description: Quota of the whole domain in MiB active: type: [integer, string] enum: [0, 1, "0", "1"] description: Domain active gal: type: [integer, string] enum: [0, 1, "0", "1"] description: Global address list in SOGo backupmx: type: [integer, string] enum: [0, 1, "0", "1"] description: Relay this domain (backup MX) relay_all_recipients: type: [integer, string] enum: [0, 1, "0", "1"] description: >- Relay all recipients, not only those with a mailbox; 1 sets `backupmx` relay_unknown_only: type: [integer, string] enum: [0, 1, "0", "1"] description: >- Relay only recipients without a local mailbox; 1 sets `backupmx` and `relay_all_recipients` tags: type: array items: type: string description: >- Tags of the domain, at most 25 (more are dropped with `tag_limit_exceeded`) rl_value: type: [integer, string] description: Rate limit, messages per `rl_frame`; empty or 0 = none rl_frame: type: string enum: [s, m, h, d] description: Rate limit time frame dkim_selector: type: string description: Selector of the DKIM key that is created key_size: type: [integer, string] description: RSA size of the new DKIM key in bits; empty or 0 = no key restart_sogo: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: Restart SOGo afterwards example: domain: example.org description: Example Org aliases: 400 mailboxes: 10 defquota: 3072 maxquota: 10240 quota: 10240 active: 1 gal: 1 backupmx: 0 relay_all_recipients: 0 relay_unknown_only: 0 tags: - customer rl_value: 100 rl_frame: h dkim_selector: dkim key_size: 2048 restart_sogo: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/domain-admin: post: summary: Create domain administrator description: >- Creates a domain administrator for the given domains with the default ACLs. The username is stored in lowercase and must not be in use by a mailbox or administrator. Without `active: 1` the account is disabled. Unknown domains are skipped; if none exists, nothing is created, but `domain_admin_added` is reported anyway. Messages: `domain_admin_added`; errors `domain_invalid`, `object_exists`, `password_complexity`, `password_mismatch`. operationId: addDomainAdmin tags: - Domain admin requestBody: required: true content: application/json: schema: type: object properties: username: type: string description: Username (letters, digits, `_`, `.`, `-`; stored in lowercase) password: type: string description: Password, must match the password policy password2: type: string description: The password again domains: description: Domain or list of domains the account administers oneOf: - type: string - type: array items: type: string active: type: [integer, string, boolean] description: 1 = the account can log in, 0 = disabled default: 0 required: - username - password - password2 - domains example: username: domainadmin1 password: "Rand0m-Passw0rd!" password2: "Rand0m-Passw0rd!" domains: - example.org - example.com active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/sso/domain-admin: post: summary: Issue domain administrator login token description: >- Issues a one-time login token for an active domain administrator, valid for 30 seconds. Opening `/domainadmin/mailbox?sso_token=` on the mailcow host logs in without password or two-factor authentication. Messages: error `object_doesnt_exist`. operationId: issueDomainAdminSsoToken tags: - Single Sign-On requestBody: required: true content: application/json: schema: type: object properties: username: type: string description: Username of the domain administrator required: - username example: username: domainadmin1 responses: "200": description: The token, or the error messages content: application/json: schema: oneOf: - type: object properties: token: type: string description: Login token (five groups of six hex digits) required: - token - $ref: "#/components/schemas/Messages" example: token: 591F6D-5C3DD2-7455CD-DAF1C1-AA4FCC "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/da-acl: post: summary: Edit domain administrator ACLs description: >- Grants the ACLs in `da_acl` and revokes all others; an empty or missing `da_acl` revokes all. Messages: `acl_saved`; error `Cannot determine current ACL`. operationId: editDomainAdminAcl tags: - Domain admin requestBody: required: true content: application/json: schema: type: object properties: items: description: Username of the domain administrator, or a list of usernames oneOf: - type: string - type: array items: type: string attr: type: object properties: da_acl: description: The ACLs to grant (a single name or a list) oneOf: - $ref: "#/components/schemas/DomainAdminAcl" - type: array items: $ref: "#/components/schemas/DomainAdminAcl" required: - items - attr example: items: - domainadmin1 attr: da_acl: - syncjobs - quarantine - login_as - sogo_access - app_passwds - bcc_maps - filters - ratelimit - spam_policy - protocol_access - smtp_ip_access - mailbox_relayhost - domain_relayhost - alias_external_goto - mailbox_groups responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/domain-admin: post: summary: Edit domain administrators description: >- Changes domain administrators. Fields not sent keep their value, but `force_tfa` and `force_pw_update` are reset to 0. `domains` replaces the domain list, empty keeps it; an empty `password` keeps the password. FIDO2 keys are not moved on rename. A password error ends the call after the domains were saved. Messages: `domain_admin_modified`; errors `domain_invalid`, `username_invalid`, `password_mismatch`, `password_complexity`. operationId: editDomainAdmin tags: - Domain admin requestBody: required: true content: application/json: schema: type: object properties: items: description: Username of the domain administrator, or a list of usernames oneOf: - type: string - type: array items: type: string attr: type: object properties: active: type: [integer, string, boolean] description: 1 = active, 0 = disabled username_new: type: string description: New username (letters, digits, `_`, `.`, `-`) domains: description: The domains the account administers from now on oneOf: - type: string - type: array items: type: string password: type: string description: New password; empty or missing keeps the password password2: type: string description: The new password again force_tfa: type: [integer, string, boolean] description: 1 = two-factor authentication must be set up at the next login default: 0 force_pw_update: type: [integer, string, boolean] description: 1 = the password must be changed at the next login default: 0 disable_tfa: type: [integer, string, boolean] description: Present (any value) = turn off two-factor authentication required: - items - attr example: items: - domainadmin1 attr: active: 1 domains: - example.org password: "N3w-Passw0rd!" password2: "N3w-Passw0rd!" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/domain-policy: post: summary: Add a sender to a domain allow or deny list description: >- Adds a sender to the allow list (`wl`) or deny list (`bl`) of a domain; a sender can be on only one list. Needs the ACL `spam_policy`. Messages: `domain_modified`; errors `policy_list_from_invalid`, `policy_list_from_exists`. operationId: addDomainPolicy tags: - Domain antispam policies requestBody: required: true content: application/json: schema: type: object required: - domain - object_list - object_from properties: domain: type: string description: Domain the entry belongs to object_list: type: string enum: [wl, bl] description: "`wl` allow list (whitelist), `bl` deny list (blacklist)" object_from: type: string description: >- Sender address or pattern with `*` as wildcard; letters, digits and `@ _ . - *` example: domain: example.org object_list: wl object_from: "*@partner.example.com" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/fwdhost: post: tags: - Forwarding Hosts summary: Add forwarding hosts operationId: addForwardingHost description: >- Adds hosts whose mail is accepted unconditionally: no DNSBL checks, no greylisting, no spam rejects. A name becomes one entry per address of its SPF record, else its MX hosts, else A/AAAA. Messages: `forwarding_host_added`; errors `invalid_host`. requestBody: content: application/json: schema: type: object properties: hostname: type: string description: >- IPv4 or IPv6 address, network in CIDR notation, host name or domain name filter_spam: type: [boolean, integer, string] description: 1 = scan the mail for spam (junk folder, never rejected); else not default: 0 required: - hostname example: hostname: relay.example.com filter_spam: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/fwdhost: post: tags: - Forwarding Hosts summary: Update forwarding hosts operationId: editForwardingHost description: >- Turns the spam filter of forwarding hosts on or off; without `keep_spam` it is turned on. requestBody: content: application/json: schema: type: object properties: items: description: >- Hosts as get/fwdhost lists them (`host`), a single value or a list oneOf: - type: array items: type: string - type: string attr: type: object properties: keep_spam: type: [boolean, integer, string] description: 1 = do not scan the mail for spam; else scan it required: - items - attr example: items: - 192.0.2.25 - "2001:db8::25" attr: keep_spam: "0" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/mailbox: post: tags: - Mailboxes summary: Create a mailbox operationId: addMailbox description: >- Creates a mailbox, also for domain admins. Quotas are in MiB. Fields not sent come from the mailbox template in `template` (default: `Default`). Quota 0 (unlimited) needs the `unlimited_quota` ACL. Messages: `mailbox_added`; errors `object_exists`, `domain_not_found`, `password_complexity`, `max_mailbox_exceeded`, `mailbox_quota_exceeded`. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MailboxAdd" example: local_part: john.doe domain: example.org name: John Doe password: Moo2Shoh5aiXu password2: Moo2Shoh5aiXu quota: 3072 active: 1 force_pw_update: 1 tags: - sales acl: - spam_alias - spam_score - delimiter_action - app_passwds responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/mailbox-group: post: summary: Create mailbox group description: >- Creates a mailbox group. With an address it is also a distribution list to its members; the address counts against the alias limit of the domain. Domain admins need the `mailbox_groups` ACL. Follow-up steps that fail answer a warning and are retried later. Messages: `group_added`; warnings `group_template_failed`, `group_imap_grant_failed`; errors `object_exists`, `group_address_invalid`, `max_alias_exceeded`, `group_member_invalid`. operationId: addMailboxGroup tags: - Groups requestBody: content: application/json: schema: allOf: - type: object required: - domain - name properties: domain: type: string description: Domain of the group (no alias domain), case-insensitive - $ref: "#/components/schemas/MailboxGroupAttributes" example: domain: example.org name: Sales description: Sales team local_part: sales members: - alice@example.org - bob@example.org send_as: - orders@example.org sender_allowed: 1 imap_grants: - owner: shared@example.org rights: write subscribe: 1 template_id: 3 priority: 10 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/oauth2-client: post: summary: Create OAuth2 client description: >- Creates an OAuth2 client with random ID and secret; read them with `get/oauth2-client/all`. The redirect URI is not validated. Messages: `Added client access`. operationId: addOAuth2Client tags: - oAuth Clients requestBody: required: true content: application/json: schema: type: object properties: redirect_uri: type: string description: Redirect (callback) URL of the client application required: - redirect_uri example: redirect_uri: https://app.example.org/oauth/callback responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/recipient_map: post: tags: - Address Rewriting summary: Create a recipient map operationId: addRecipientMap description: >- Rewrites the recipient before delivery: mail to `recipient_map_old` goes to `recipient_map_new`. Messages: `recipient_map_entry_saved`; errors `invalid_recipient_map_old`, `invalid_recipient_map_new`, `recipient_map_entry_exists`. requestBody: content: application/json: schema: type: object properties: recipient_map_old: type: string description: Original recipient, an e-mail address or a domain (leading `@` optional) recipient_map_new: type: string description: New recipient, an e-mail address or a domain active: type: [boolean, integer, string] description: 1 = active, 0 = inactive default: 0 required: - recipient_map_old - recipient_map_new example: recipient_map_old: jane.doe@example.org recipient_map_new: jane.smith@example.org active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/relayhost: post: tags: - Routing summary: Create a sender-dependent transport operationId: addRelayhost description: >- Adds an active relay host, used by domains and mailboxes whose `relayhost` is set to its ID. Always `smtp:` (TLS when offered, no SMTPS). Colons in `username` and `password` are stored escaped, but not by edit/relayhost. Messages: `relayhost_added`; errors `invalid_host`. requestBody: content: application/json: schema: type: object properties: hostname: type: string description: "Next hop: `host`, `host:25`, `[host]:587` or `[192.0.2.1]:25`" username: type: string description: SMTP user name, empty for no authentication default: "" password: type: string description: SMTP password default: "" required: - hostname example: hostname: "[smtp.example.com]:587" username: relay-user@example.com password: Secret-Passphrase-42 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/resource: post: tags: - Resources summary: Create a resource operationId: addResource description: >- Creates a bookable SOGo resource, also for domain admins. Its address is made of the letters and digits of `description` (`Meeting Room 1` → `MeetingRoom1@example.org`). Messages: `resource_added`; errors `resource_invalid`, `description_invalid`, `object_exists`. requestBody: required: true content: application/json: schema: type: object required: - domain - description - kind properties: domain: type: string description: Domain of the resource description: type: string description: Name of the resource, also the source of its address kind: type: string enum: - location - group - thing description: Type of resource multiple_bookings: type: [integer, string] default: 0 description: >- 0 always free, -1 unlimited but busy when booked, n ≥ 1 at most n overlapping bookings; below -1 means -1 active: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: 1 active, 0 inactive example: domain: example.org description: Meeting Room 1 kind: location multiple_bookings: 0 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/syncjob: post: summary: Create sync job description: >- Creates a sync job that copies the remote account `user1` into a local mailbox; server and authentication come from the sync source. Needs the `syncjobs` ACL; API keys must set `username`, users always sync into their own mailbox. An invalid `mins_interval` or `exclude` answers `access_denied`. Messages: `mailbox_modified`; errors `no_user_defined`, `imapsync_source_unavailable`, `imapsync_source_oauth_connect_required`, `object_exists`, `imapsync_custom_param_invalid`. operationId: addSyncJob tags: - Sync jobs requestBody: content: application/json: schema: allOf: - type: object required: - username - source_id - user1 - mins_interval properties: username: type: string description: >- Local mailbox to sync into (`user2`), cannot be changed later; users may leave it out - $ref: "#/components/schemas/SyncJobAttributes" example: username: alice@example.org source_id: 3 user1: alice@old-provider.example.com password1: remote-password mins_interval: 20 subfolder2: Imported exclude: "(?i)spam|(?i)junk" custom_params: - o: folder v: INBOX delete2duplicates: 1 automap: 1 subscribeall: 1 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/syncjob_source: post: summary: Create sync source description: >- Creates a reusable IMAP server with its authentication that sync jobs use by `source_id`. Needs the `syncjobs` ACL. Unless an admin creates it, OAuth2 endpoints must resolve to public addresses. A client_credentials source fetches its token on save and is saved even when that fails. Messages: `imapsync_source_added`, `imapsync_source_token_refresh_failed`; errors `imapsync_source_host_invalid`, `imapsync_source_auth_invalid`, `imapsync_source_oauth_invalid`, `imapsync_source_oauth_endpoint_invalid`, `object_exists`. operationId: addSyncJobSource tags: - Sync jobs requestBody: content: application/json: schema: allOf: - type: object required: - name - host - port - $ref: "#/components/schemas/SyncJobSourceAttributes" examples: password: summary: Password source for a domain value: name: Old provider description: Migration from the old provider host: imap.example.com port: 993 enc: SSL auth_type: PLAIN scope: domain domains: - example.org active: 1 client_credentials: summary: XOAUTH2 source with an app token (Microsoft 365) value: name: M365 tenant host: outlook.office365.com port: 993 enc: SSL auth_type: XOAUTH2 oauth_flow: client_credentials oauth_token_endpoint: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token oauth_client_id: 11111111-2222-3333-4444-555555555555 oauth_client_secret: client-secret-value oauth_scope: https://outlook.office365.com/.default active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/tls-policy-map: post: tags: - Outgoing TLS Policy Map Overrides summary: Create a TLS policy map operationId: addTlsPolicyMap description: >- Sets the TLS policy for outgoing connections to a destination. Messages: `tls_policy_map_entry_saved`; errors `tls_policy_map_dest_invalid`, `tls_policy_map_parameter_invalid`, `tls_policy_map_entry_exists`. requestBody: content: application/json: schema: type: object properties: dest: type: string description: >- Destination: a domain, `.example.org` for its subdomains or a host like `[mail.example.org]:25` policy: type: string description: >- Postfix TLS security level (see [smtp_tls_policy_maps](https://www.postfix.org/TLS_README.html#client_tls_policy)) enum: - none - may - encrypt - dane - dane-only - fingerprint - verify - secure parameters: type: string description: Space-separated `name=value` attributes, may be empty default: "" active: type: [boolean, integer, string] description: 1 = active, 0 = inactive default: 0 required: - dest - policy example: dest: example.com policy: encrypt parameters: protocols=>=TLSv1.2 active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/transport: post: tags: - Routing summary: Create transport maps operationId: addTransport description: >- Routes mail for each destination over a next hop; overrules sender-dependent transports. Always `smtp:` (TLS when offered, no SMTPS); addresses ending in `localhost` stay local. `username` and `password` apply to all entries of the next hop. Messages: `relayhost_added`; errors `transport_dest_exists`, `invalid_destination`, `next_hop_interferes`, `invalid_nexthop_authenticated`. requestBody: content: application/json: schema: type: object properties: destination: type: string description: >- Domains, `.example.org` for subdomains, `*` or addresses, separated by spaces, commas, semicolons or line breaks; with `is_mx_based` a regular expression for the MX name of the recipient domain nexthop: type: string description: "`host`, `host:25`, `[host]:25` or an IP address (bracketed automatically)" username: type: string description: SMTP user name, empty for no authentication default: "" password: type: string description: SMTP password default: "" is_mx_based: type: [boolean, integer, string] description: 1 = `destination` is a regular expression for MX names default: 0 active: type: [boolean, integer, string] description: 1 = active, 0 = inactive default: 0 required: - destination - nexthop example: destination: example.com, .example.com nexthop: "[mx.example.com]:25" username: "" password: "" is_mx_based: "0" active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/alias: post: tags: - Aliases summary: Delete aliases operationId: deleteAlias description: >- Deletes the aliases and the send-as rights granted for their addresses. Distribution addresses of mailbox groups cannot be deleted here. Messages: `alias_removed`; errors `alias_group_managed`. requestBody: content: application/json: schema: type: array description: IDs or addresses of the aliases (a single value works too) items: type: [integer, string] example: - 12 - info@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/api-key: post: summary: Delete API keys description: >- Deletes API keys. Service keys from mailcow.conf cannot be deleted. Messages: `api_key_deleted`; error `api_key_service_locked`. operationId: deleteApiKey tags: - API Keys requestBody: required: true content: application/json: schema: type: array description: IDs of the API keys items: type: [integer, string] example: - 3 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/app-passwd: post: tags: - App Passwords summary: Delete app passwords operationId: deleteAppPassword description: >- Deletes app passwords by ID. Needs the user ACL `app_passwds`. The first unknown or foreign ID stops the call. requestBody: required: true content: application/json: schema: type: array description: App password IDs items: type: integer example: - 23 - 24 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/bcc: post: tags: - Address Rewriting summary: Delete BCC maps operationId: deleteBccMap description: >- Deletes BCC maps by ID. Same callers as add/bcc. A non-numeric ID stops the call. Messages: `bcc_deleted`. requestBody: content: application/json: schema: type: array description: IDs of the BCC maps (a single value works too) items: type: [integer, string] example: - 3 - 4 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/dkim: post: summary: Delete DKIM keys description: >- Deletes the DKIM keys of domains. Answers `dkim_removed` also for domains without a key. operationId: deleteDkimKeys tags: - DKIM requestBody: required: true content: application/json: schema: type: array description: Domain names items: type: string example: - example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/domain: post: summary: Delete domains description: >- Deletes domains without mailboxes or resources, with their aliases, alias domains and settings. Domain admins left without a domain are deleted too. The DKIM key is kept. Messages: `domain_removed`; error `domain_not_empty`. operationId: deleteDomain tags: - Domains requestBody: required: true content: application/json: schema: type: array description: Domain names items: type: string example: - example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/domain-admin: post: summary: Delete domain administrators description: >- Deletes domain administrators with their ACLs, two-factor authentication and FIDO2 keys. Messages: `domain_admin_removed`; error `username_invalid`. operationId: deleteDomainAdmin tags: - Domain admin requestBody: required: true content: application/json: schema: type: array description: Usernames of the domain administrators items: type: string example: - domainadmin1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/domain-policy: post: summary: Delete entries of domain allow and deny lists description: >- Deletes allow and deny list entries of domains by `prefid`. Needs the ACL `spam_policy`. Unknown IDs and entries of mailboxes answer `access_denied`. Messages: `item_deleted`. operationId: deleteDomainPolicy tags: - Domain antispam policies requestBody: required: true content: application/json: schema: type: array description: Entry IDs (`prefid`) items: type: [integer, string] example: - 12 - 13 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/fwdhost: post: tags: - Forwarding Hosts summary: Delete forwarding hosts operationId: deleteForwardingHost description: >- Removes forwarding hosts, answering `forwarding_host_removed` also for hosts that do not exist. requestBody: content: application/json: schema: type: array description: Hosts as get/fwdhost lists them (`host`; a single value works too) items: type: string example: - 192.0.2.25 - "2001:db8::25" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/fwdhost/{host}: get: tags: - Forwarding Hosts summary: Get forwarding hosts operationId: getForwardingHosts description: >- `all` lists the forwarding hosts; any logged-in role may read a single address. Networks cannot be read one by one (the slash ends the path). `{}` if there is none. parameters: - name: host in: path required: true description: "`all` or the address of a forwarding host" schema: type: string example: all responses: "200": description: The list of forwarding hosts (`all`) or one host content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/ForwardingHost" - $ref: "#/components/schemas/ForwardingHost" examples: all: summary: get/fwdhost/all value: - host: 192.0.2.25 source: relay.example.com keep_spam: "no" - host: "2001:db8::25" source: relay.example.com keep_spam: "no" - host: 198.51.100.0/24 source: 198.51.100.0/24 keep_spam: "yes" one: summary: get/fwdhost/192.0.2.25 value: host: 192.0.2.25 source: relay.example.com keep_spam: "no" "401": $ref: "#/components/responses/Unauthorized" /api/v1/delete/mailbox: post: tags: - Mailboxes summary: Delete mailboxes operationId: deleteMailbox description: >- Deletes mailboxes with all their data, including aliases that point only to them. Also for domain admins; a mailbox user can delete its own mailbox. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MailboxItems" example: - john.doe@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/mailbox-group: post: summary: Delete mailbox groups description: >- Deletes groups with their address, send-as rights and grants. Members keep their mailbox settings; another group's template may become effective. Same permissions as edit. Messages: `group_removed`. operationId: deleteMailboxGroups tags: - Groups requestBody: content: application/json: schema: type: array description: Group ids items: type: - integer - string example: - 7 - 8 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/identity-link: post: summary: Remove identity links description: >- Removes the links of mailboxes to their Identity Provider users, e.g. after an address moved to another user; the next sync run or login links them again by email. Answers success also for mailboxes without a link. Messages: `iam_link_removed`. operationId: deleteIdentityLinks tags: - Identity Provider requestBody: content: application/json: schema: type: array description: Mailboxes items: type: string example: - alice@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/mailq: post: summary: Delete queued messages description: >- Deletes messages from the Postfix queue. To empty the whole queue use `super_delete` of `POST /api/v1/edit/mailq`. Messages: `queue_command_success`; errors `Error: command failed: ...`, `unknown`. operationId: deleteQueuedMessages tags: - Queue Manager requestBody: content: application/json: schema: description: Queue IDs (a single ID works too) oneOf: - type: array items: type: string - type: string example: - B98C6260CA1 - 4C1E8260D02 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/oauth2-client: post: summary: Delete OAuth2 clients description: >- Deletes OAuth2 clients but not their tokens; revoke these first with `revoke_tokens` of `edit/oauth2-client`. Messages: `items_deleted`. operationId: deleteOAuth2Client tags: - oAuth Clients requestBody: required: true content: application/json: schema: type: array description: IDs of the clients items: type: [integer, string] example: - 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/qitem: post: summary: Delete quarantined messages description: >- Deletes quarantine items without releasing or learning them. Domain admins and mailbox users may delete their own items if the quarantine module is allowed for them. Admins get `item_deleted` even for unknown IDs. operationId: deleteQuarantineItems tags: - Quarantine requestBody: content: application/json: schema: description: IDs of quarantine items (a single ID works too) oneOf: - type: array items: type: [integer, string] - type: [integer, string] example: - "33" - "34" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/qitem: post: summary: Release or learn quarantined messages description: >- By `attr.action`: `release` and `learnham` both deliver the message, delete the item and learn it as ham; `learnspam` deletes it and learns it as spam. Domain admins and mailbox users may act on their own items if the quarantine module is allowed for them. A failed delivery stops the remaining items. Messages: `item_released`, `learned_ham`, `qlearn_spam`; errors `release_send_failed`, `ham_learn_error`, `spam_learn_error`. operationId: editQuarantineItems tags: - Quarantine requestBody: content: application/json: schema: type: object properties: items: description: ID or list of IDs of quarantine items oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: action: type: string enum: - release - learnham - learnspam required: - action required: - items - attr example: items: - "33" - "34" attr: action: release responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/recipient_map: post: tags: - Address Rewriting summary: Delete recipient maps operationId: deleteRecipientMap description: >- Deletes recipient maps by ID. Answers `recipient_map_entry_deleted` also for IDs that do not exist; a non-numeric ID stops the call. requestBody: content: application/json: schema: type: array description: IDs of the recipient maps (a single value works too) items: type: [integer, string] example: - 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/relayhost: post: tags: - Routing summary: Delete sender-dependent transports operationId: deleteRelayhost description: >- Deletes sender-dependent transports by ID, answering `relayhost_removed` also for IDs that do not exist. Domains that used one fall back to the default route; the `relayhost` of mailboxes is not reset. requestBody: content: application/json: schema: type: array description: IDs of the sender-dependent transports (a single value works too) items: type: [integer, string] example: - 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/resource: post: tags: - Resources summary: Delete resources operationId: deleteResource description: >- Deletes resources and their SOGo data, also for domain admins. requestBody: required: true content: application/json: schema: type: array description: Resource addresses items: type: string example: - MeetingRoom1@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/syncjob: post: summary: Delete sync jobs description: >- Deletes sync jobs. Needs the `syncjobs` ACL and access to the mailbox of each job. The OAuth2 token of the remote account is deleted when no other job uses it. Messages: `deleted_syncjob`. operationId: deleteSyncJobs tags: - Sync jobs requestBody: content: application/json: schema: type: array description: Job ids items: type: - integer - string example: - 12 - 13 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/syncjob_source: post: summary: Delete sync sources description: >- Deletes sync sources that no job uses. Needs the `syncjobs` ACL and edit rights on the source. Messages: `imapsync_source_deleted`; errors `imapsync_source_in_use`. operationId: deleteSyncJobSources tags: - Sync jobs requestBody: content: application/json: schema: type: array description: Source ids items: type: - integer - string example: - 3 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/tls-policy-map: post: tags: - Outgoing TLS Policy Map Overrides summary: Delete TLS policy maps operationId: deleteTlsPolicyMap description: >- Deletes TLS policy maps by ID. Answers `tls_policy_map_entry_deleted` also for IDs that do not exist; a non-numeric ID stops the call. requestBody: content: application/json: schema: type: array description: IDs of the TLS policy maps (a single value works too) items: type: [integer, string] example: - 2 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/transport: post: tags: - Routing summary: Delete transport maps operationId: deleteTransport description: >- Deletes transport maps by ID, answering `relayhost_removed` also for IDs that do not exist. requestBody: content: application/json: schema: type: array description: IDs of the transport maps (a single value works too) items: type: [integer, string] example: - 4 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/mailbox/tag/{mailbox}: post: tags: - Mailboxes summary: Remove tags from a mailbox operationId: deleteMailboxTags description: >- Removes tags from the mailbox, also for domain admins. Answers "Cannot delete item" when no tag was sent. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org requestBody: required: true content: application/json: schema: type: array description: Tag names items: type: string example: - sales - trainee responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/domain/tag/{domain}: post: summary: Remove tags of a domain description: >- Removes tags from a domain. Answers `domain_modified` also for tags the domain did not have. operationId: deleteDomainTags tags: - Domains parameters: - name: domain in: path required: true description: Domain name schema: type: string example: example.org requestBody: required: true content: application/json: schema: type: array description: Tag names items: type: string example: - customer responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/alias: post: tags: - Aliases summary: Update aliases operationId: editAlias description: >- Changes the aliases in `items`; fields not sent keep their value, except the `goto_*` flags, which are reset to 0. An alias that discards or learns its mail therefore needs its `goto_*` flag in every edit, else nothing is saved while the answer still says `alias_modified`. Invalid destinations are dropped; if none remains, nothing is saved. Messages: `alias_modified`; errors `alias_invalid`, `alias_group_managed`, `goto_invalid`, `is_not_primary_alias`. requestBody: content: application/json: schema: type: object properties: items: description: IDs or addresses of the aliases, a single value or a list oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: address: type: string description: New alias address, `@example.org` for a catch-all goto: type: string description: >- New destination addresses, replacing the current ones; ignored if a `goto_*` flag is 1 goto_null: type: [boolean, integer, string] description: 1 = discard the mail silently default: 0 goto_spam: type: [boolean, integer, string] description: 1 = learn the mail as spam default: 0 goto_ham: type: [boolean, integer, string] description: 1 = learn the mail as ham default: 0 active: type: [boolean, integer, string] description: 1 = active, 0 = inactive sogo_visible: type: [boolean, integer, string] description: 1 = selectable sender in SOGo internal: type: [boolean, integer, string] description: 1 = only reachable from its own domain and its alias domains sender_allowed: type: [boolean, integer, string] description: 1 = the destination mailboxes may send as this alias public_comment: type: string description: Comment shown to the users private_comment: type: string description: Comment for administrators expand_alias: type: [boolean, integer] description: >- 1 = only create the missing copies of the alias in the alias domains of its domain; other attributes are ignored required: - items - attr example: items: - 12 attr: goto: anna@example.org,ben@example.org,carla@example.org active: "1" public_comment: Sales team responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/api-key: post: summary: Edit API keys description: >- Changes API keys; fields not sent keep their value. `regen_key` sets a new random value, which locks out clients using the old one. Service keys from mailcow.conf cannot be changed. Messages: `api_key_modified`; errors `api_key_service_locked`, `api_key_network_invalid`, `ip_list_empty`. operationId: editApiKey tags: - API Keys requestBody: required: true content: application/json: schema: type: object properties: items: description: ID of the API key, or a list of IDs oneOf: - type: [integer, string] - type: array items: type: [integer, string] attr: allOf: - $ref: "#/components/schemas/ApiKeyAttributes" - type: object properties: regen_key: type: [integer, string, boolean] description: 1 = generate a new key value default: 0 required: - items - attr example: items: - 3 attr: allow_from: - 192.0.2.10 - 198.51.100.0/24 regen_key: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/domain: post: summary: Edit domains description: >- Changes domains. Quotas are in MiB. Fields not sent keep their value, so do `aliases`, `maxquota` and `quota` sent as 0 or empty. `tags` are added; a tag the domain has already ends the call without an answer after saving the rest. Domain admins can change only `description`, `gal` and `tags`. Messages: `domain_modified`; errors `domain_invalid`, `max_quota_in_use`, `mailboxes_in_use`, `aliases_in_use`. operationId: editDomain tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Domain name or list of domain names oneOf: - type: string - type: array items: type: string attr: type: object properties: description: type: string description: Description aliases: type: [integer, string] description: Max. number of aliases mailboxes: type: [integer, string] description: Max. number of mailboxes defquota: type: [integer, string] description: Default quota of new mailboxes in MiB maxquota: type: [integer, string] description: Max. quota per mailbox in MiB quota: type: [integer, string] description: Quota of the whole domain in MiB active: type: [integer, string] enum: [0, 1, "0", "1"] description: Domain active gal: type: [integer, string] enum: [0, 1, "0", "1"] description: Global address list in SOGo backupmx: type: [integer, string] enum: [0, 1, "0", "1"] description: Relay this domain (backup MX) relay_all_recipients: type: [integer, string] enum: [0, 1, "0", "1"] description: Relay all recipients; 1 sets `backupmx` relay_unknown_only: type: [integer, string] enum: [0, 1, "0", "1"] description: >- Relay only recipients without a local mailbox; 1 sets `backupmx` and `relay_all_recipients` relayhost: type: [integer, string] description: >- ID of the sender-dependent transport (get/relayhost/all) the domain sends through, 0 = none tags: type: array items: type: string description: Tags to add example: items: - example.org attr: description: Example Org aliases: 400 mailboxes: 20 defquota: 3072 maxquota: 10240 quota: 51200 active: 1 gal: 1 backupmx: 0 relay_all_recipients: 0 relay_unknown_only: 0 relayhost: 0 tags: - premium responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/domain/footer: post: summary: Set the domain-wide footer description: >- Sets the footer of all outgoing mail of the domains; fields not sent are emptied. Placeholders: `{= auth_user =}`, `{= from_user =}`, `{= from_name =}`, `{= from_addr =}`, `{= from_domain =}` and custom mailbox attributes. Messages: `domain_footer_modified`; error `domain_invalid`. operationId: editDomainFooter tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Domain name or list of domain names oneOf: - type: string - type: array items: type: string attr: type: object properties: html: type: string default: "" description: HTML footer plain: type: string default: "" description: Plain text footer skip_replies: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: No footer in replies exclude: description: >- Mailboxes, aliases and alias domains without footer; unknown entries are skipped (`username_invalid`) oneOf: - type: string - type: array items: type: string example: items: - example.org attr: html: "

Example Org · {= from_name =}

" plain: "Example Org - {= from_name =}" skip_replies: 1 exclude: - noreply@example.org - example.com responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/fail2ban: post: summary: Edit Fail2Ban settings, bans and filters description: >- By `attr.action`: `unban`, `whitelist` and `blacklist` unban, allowlist or deny the networks in `items`; `unban-all` lifts all active bans; `edit-regex` replaces the regex filters with `attr.regex`, `reset-regex` restores the defaults. Without `action` the settings are saved: fields not sent keep their value, but `ban_time_increment` and `manage_external` become 0, and values out of range are clamped. The same happens for `unban`, `whitelist`, `blacklist` or `reset-regex` without `items`. Messages: `f2b_modified`, `object_modified`; errors `network_host_invalid`, `reset_f2b_regex`. operationId: editFail2Ban tags: - Fail2Ban requestBody: content: application/json: schema: type: object properties: items: description: Networks or IPs for `unban`, `whitelist`, `blacklist` (single value or list) oneOf: - type: array items: type: string - type: string attr: type: object properties: action: type: string enum: - unban - whitelist - blacklist - unban-all - edit-regex - reset-regex regex: type: array items: type: string description: "`edit-regex`: the regex filters; the first group must match the IP" ban_time: type: [integer, string] description: Ban time in seconds (min. 60) ban_time_increment: type: [boolean, integer, string] description: 1 = the ban time grows with every ban of a network; not sent = 0 max_ban_time: type: [integer, string] description: Maximum ban time in seconds (min. 60) max_attempts: type: [integer, string] description: Failed logins within `retry_window` that lead to a ban (min. 1) retry_window: type: [integer, string] description: Window in seconds for `max_attempts` (min. 1) netban_ipv4: type: [integer, string] description: IPv4 prefix length that is banned (8-32) netban_ipv6: type: [integer, string] description: IPv6 prefix length that is banned (8-128) whitelist: type: string description: Allowlist, networks or host names separated by space, comma, semicolon or newline; replaces the list blacklist: type: string description: Denylist, networks separated by space, comma, semicolon or newline; replaces the list manage_external: type: [boolean, integer, string] description: 1 = netfilter sets no rules, block externally with the banlist; not sent = 0 required: - attr examples: settings: summary: Save the settings value: items: [] attr: ban_time: "1800" ban_time_increment: "1" max_ban_time: "86400" max_attempts: "10" retry_window: "600" netban_ipv4: "32" netban_ipv6: "128" whitelist: |- 192.0.2.0/24 mail.example.org blacklist: 198.51.100.66/32 manage_external: "0" unban: summary: Unban a network value: items: - 203.0.113.7/32 attr: action: unban regex: summary: Replace the regex filters value: items: - self attr: action: edit-regex regex: - "^mailcow UI: Invalid password for .+ by ([0-9a-f\\.:]+)$" - "^Rspamd UI: Invalid password by ([0-9a-f\\.:]+)$" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/mailbox: post: tags: - Mailboxes summary: Update mailboxes operationId: editMailbox description: >- Changes mailboxes; fields not sent keep their value. Also for domain admins; without the matching ACL their changes to `sogo_access`, protocols and `relayhost` are ignored silently and `extended_sender_acl` is refused. Quota 0 (unlimited) needs the `unlimited_quota` ACL. Messages: `mailbox_modified`; errors `mailbox_quota_exceeded`, `password_complexity`, `sender_acl_invalid`, `extended_sender_acl_denied`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: $ref: "#/components/schemas/MailboxEdit" example: items: - john.doe@example.org attr: name: John Doe quota: 5120 active: 1 protocol_access: - imap - smtp - sieve - dav sender_acl: - sales@example.org - "@example.com" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/mailbox/custom-attribute: post: tags: - Mailboxes summary: Set custom attributes of mailboxes operationId: editMailboxCustomAttributes description: >- Replaces the custom attributes (free key/value pairs) of the mailboxes: `attribute[i]` gets `value[i]`, all others are removed. Also for domain admins. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object properties: attribute: description: Attribute names (a single string is one name) oneOf: - type: string - type: array items: type: string value: description: Values, in the order of `attribute` oneOf: - type: string - type: array items: type: string example: items: - john.doe@example.org attr: attribute: - department - employee_id value: - Sales - "4711" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/mailbox-group: post: summary: Update mailbox groups description: >- Changes groups; fields not sent keep their value. The domain cannot be changed, and members from the identity sync cannot be removed here. Domain admins need the `mailbox_groups` ACL and cannot edit groups with send-as addresses or grants outside their domains. Messages: `group_modified`; errors `group_member_idp` and those of add. operationId: editMailboxGroups tags: - Groups requestBody: content: application/json: schema: type: object required: - items - attr properties: items: description: >- Group ids, a list or a single id. An `id` inside `attr` replaces `items`. oneOf: - type: array items: type: - integer - string - type: - integer - string attr: allOf: - $ref: "#/components/schemas/MailboxGroupAttributes" - type: object properties: reapply_template: type: - boolean - integer - string description: >- Admins only: apply the effective templates to all members again, also when nothing changed default: 0 example: items: - 7 attr: add_members: - carol@example.org remove_members: - bob@example.org sogo_grants: - owner: shared@example.org type: Calendar folder: personal access: write subscribe: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/identity-provider-sync: post: summary: Request an identity sync run description: >- Queues an identity sync run (Keycloak and LDAP) that starts within a minute, see `GET /api/v1/get/identity-provider/sync-status`. An identical pending request is reused. Messages: `iam_sync_requested`; errors `iam_sync_mode_invalid`, `iam_sync_unavailable`. operationId: requestIdentitySync tags: - Identity Provider requestBody: content: application/json: schema: type: object required: - attr properties: items: description: Not used attr: type: object properties: mode: type: string description: >- `preview` lists the changes without applying them, `run` applies them, `force` applies them without the change limit (`offboarding_limit`) enum: - preview - run - force default: run example: attr: mode: preview responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/mailq: post: summary: Act on the mail queue description: >- Runs a Postfix queue command. `hold`, `unhold` and `deliver` act on the queue IDs in `items` and do nothing without them; `flush` retries the whole queue, `super_delete` deletes every queued message. Messages: `queue_command_success`; errors `Error: command failed: ...`, `unknown`. operationId: editMailQueue tags: - Queue Manager requestBody: content: application/json: schema: type: object properties: items: description: Queue ID or list of queue IDs (for `hold`, `unhold`, `deliver`) oneOf: - type: array items: type: string - type: string attr: type: object properties: action: type: string enum: - hold - unhold - deliver - flush - super_delete required: - action required: - attr examples: hold: summary: Hold two messages value: items: - B98C6260CA1 - 4C1E8260D02 attr: action: hold flush: summary: Flush the whole queue value: items: [] attr: action: flush responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/pushover: post: tags: - Mailbox user settings summary: Set the Pushover notifications of mailboxes operationId: editPushover description: >- Saves the Pushover settings (push notification on new mail) of the mailboxes; `delete: "true"` removes them. Needs the user ACL `pushover`; domain admins need their own ACL `pushover`. `key` and `token` are required the first time; later, empty fields keep their value. Messages: `pushover_settings_edited`; errors `pushover_key`, `pushover_token`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object properties: key: type: string description: Pushover user key, 30 letters and digits token: type: string description: Pushover application token, 30 letters and digits active: type: [integer, string] enum: [0, 1, "0", "1"] title: type: string description: Title of the notification (default "Mail") text: type: string description: Text of the notification senders: type: string description: Only notify for these senders (separated by comma, space or semicolon) senders_regex: type: string description: Only notify for senders matching this regular expression evaluate_x_prio: type: [integer, string] enum: [0, 1, "0", "1"] description: 1 sends high-priority mail as high-priority notification (0 when not sent) only_x_prio: type: [integer, string] enum: [0, 1, "0", "1"] description: 1 notifies for high-priority mails only (0 when not sent) sound: type: string description: Pushover sound name (empty when not sent) delete: type: string enum: - "true" description: '"true" removes the Pushover settings, other fields are ignored' example: items: - john.doe@example.org attr: key: uQiRzpo4DXghDmr9QzzfQu27cmVRsG token: azGDORePK8gMaC0QOYAMyEEuzJnyUi active: 1 title: New mail text: You've got mail senders: boss@example.org evaluate_x_prio: 1 only_x_prio: 0 sound: pushover responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/quarantine_notification: post: tags: - Quarantine summary: Set the quarantine notification interval of mailboxes operationId: editQuarantineNotification description: >- How often the mailbox user gets a summary of quarantined mail. Needs the user ACL `quarantine_notification`; a mailbox user may change only its own. An invalid value answers `access_denied`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object required: - quarantine_notification properties: quarantine_notification: type: string enum: - never - hourly - daily - weekly example: items: - john.doe@example.org attr: quarantine_notification: daily responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/syncjob: post: summary: Update sync jobs description: >- Changes sync jobs; fields not sent keep their value, an empty `user1` or `password1` keeps the stored one. The local mailbox cannot be changed. Needs the `syncjobs` ACL and access to the mailbox of each job. Messages: `mailbox_modified`; errors as for add. operationId: editSyncJobs tags: - Sync jobs requestBody: content: application/json: schema: type: object required: - items - attr properties: items: description: >- Job ids, a list or a single id. An `id` inside `attr` replaces `items`. oneOf: - type: array items: type: - integer - string - type: - integer - string attr: allOf: - $ref: "#/components/schemas/SyncJobAttributes" - type: object properties: last_run: description: Any value except null resets the last run time (the job is due again) success: description: Any value except null resets the result of the last run prio: type: - integer - string description: >- Admins only: queue priority, higher runs first (see `edit/syncjob/run_next`) example: items: - 12 - 13 attr: active: 0 mins_interval: 60 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/syncjob/run_next: post: summary: Run sync jobs next description: >- Moves sync jobs to the front of the queue so the runner starts them next; their `last_run` and `success` are cleared. Messages: `imapsync_run_next_done`; errors `imapsync_job_running`. operationId: runSyncJobsNext tags: - Sync jobs requestBody: content: application/json: schema: type: object required: - items properties: items: description: Job ids type: array items: type: - integer - string attr: description: Not used type: object example: items: - 12 attr: {} responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/syncjob_source: post: summary: Update sync sources description: >- Changes sync sources; fields not sent keep their value, an empty `oauth_client_secret` keeps the stored one. Needs the `syncjobs` ACL and edit rights: own sources, for domain admins also those of their mailboxes. Changing the server or OAuth2 client drops stored tokens and, like turning off `verify_cert`, needs access to every mailbox whose jobs use the source. Messages: `imapsync_source_modified`, `imapsync_source_token_refresh_failed`; errors `imapsync_source_used_by_others` and those of add. operationId: editSyncJobSources tags: - Sync jobs requestBody: content: application/json: schema: type: object required: - items - attr properties: items: description: >- Source ids, a list or a single id. An `id` inside `attr` replaces `items`. oneOf: - type: array items: type: - integer - string - type: - integer - string attr: $ref: "#/components/schemas/SyncJobSourceAttributes" example: items: - 3 attr: description: Migration finished in December scope: user users: - alice@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/syncjob_source/refresh_token: post: summary: Refresh the token of a sync source description: >- Fetches a new OAuth2 token for a client_credentials source now; tokens are otherwise refreshed before they expire. Needs the `syncjobs` ACL and edit rights on the source. Messages: `imapsync_source_token_refreshed`; errors `imapsync_source_refresh_unsupported`, `imapsync_source_token_refresh_failed`. operationId: refreshSyncJobSourceToken tags: - Sync jobs requestBody: content: application/json: schema: type: object required: - items properties: items: description: Source id (the first entry is used) type: array items: type: - integer - string attr: description: Not used type: object example: items: - 5 attr: {} responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/imapsync_settings: post: summary: Update global sync job settings description: >- Sets how many sync jobs run at the same time and the bandwidth limit of each sync job process; a lower `maxbytespersecond` of a job still applies. Messages: `max_parallel_saved`; errors `imapsync_max_parallel_invalid`, `imapsync_max_kb_per_second_invalid`. operationId: editSyncJobSettings tags: - Sync jobs requestBody: content: application/json: schema: type: object required: - attr properties: items: description: Not used attr: type: object required: - max_parallel properties: max_parallel: type: - integer - string description: Sync jobs running at the same time, 1-32 minimum: 1 maximum: 32 max_kb_per_second: type: - integer - string description: Bandwidth limit per sync job process in KB/s; 0, empty or not sent = unlimited default: 0 minimum: 0 maximum: 10485760 example: attr: max_parallel: 4 max_kb_per_second: 2000 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/user-acl: post: tags: - Mailboxes summary: Set the ACL of mailboxes operationId: editUserAcl description: >- Sets the user ACL (what the mailbox user may change in the UI): listed ACLs on, all others off. Domain admins can change only ACLs they have themselves. Answers `acl_saved`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object properties: user_acl: description: ACLs to switch on (a single string is one ACL); an empty list switches all off oneOf: - $ref: "#/components/schemas/UserAclName" - type: array items: $ref: "#/components/schemas/UserAclName" example: items: - john.doe@example.org attr: user_acl: - spam_alias - tls_policy - spam_score - spam_policy - delimiter_action - eas_reset - pushover - quarantine - quarantine_notification - app_passwds - pw_reset responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/alias/{id}: get: tags: - Aliases summary: Get aliases operationId: getAliases description: >- `all` lists the aliases of the domains the caller manages, an ID or address returns one alias. Mailbox addresses are not listed. `{}` if there is none. parameters: - name: id in: path required: true description: "`all`, or the ID or address of an alias" schema: type: string example: all responses: "200": description: The list of aliases (`all`) or one alias content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/Alias" - $ref: "#/components/schemas/Alias" examples: all: summary: get/alias/all value: - in_primary_domain: "" id: 12 domain: example.org public_comment: Sales team private_comment: null goto: anna@example.org,ben@example.org address: sales@example.org is_catch_all: 0 internal: 0 active: 1 active_int: 1 sogo_visible: 1 sogo_visible_int: 1 sender_allowed: 1 group_id: null group_name: null created: "2026-10-26 14:43:58" modified: "2026-11-08 20:38:01" - in_primary_domain: example.org id: 20 domain: example.net public_comment: "" private_comment: "" goto: null@localhost address: "@example.net" is_catch_all: 1 internal: 0 active: 1 active_int: 1 sogo_visible: 0 sogo_visible_int: 0 sender_allowed: 0 group_id: null group_name: null created: "2026-11-02 09:12:40" modified: null one: summary: get/alias/12 value: in_primary_domain: "" id: 12 domain: example.org public_comment: Sales team private_comment: null goto: anna@example.org,ben@example.org address: sales@example.org is_catch_all: 0 internal: 0 active: 1 active_int: 1 sogo_visible: 1 sogo_visible_int: 1 sender_allowed: 1 group_id: null group_name: null created: "2026-10-26 14:43:58" modified: "2026-11-08 20:38:01" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/alias/all/{domains}: get: tags: - Aliases summary: Get the aliases of domains operationId: getAliasesByDomain description: >- Lists the aliases of the named domains or alias domains, skipping domains the caller does not manage. `{}` if there is none. parameters: - name: domains in: path required: true description: Comma-separated domain names schema: type: string example: example.org,example.net responses: "200": description: The list of aliases content: application/json: schema: type: array items: $ref: "#/components/schemas/Alias" example: - in_primary_domain: "" id: 12 domain: example.org public_comment: Sales team private_comment: null goto: anna@example.org,ben@example.org address: sales@example.org is_catch_all: 0 internal: 0 active: 1 active_int: 1 sogo_visible: 1 sogo_visible_int: 1 sender_allowed: 1 group_id: null group_name: null created: "2026-10-26 14:43:58" modified: "2026-11-08 20:38:01" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/time_limited_aliases/{mailbox}: get: tags: - Mailbox user settings summary: Get the time-limited aliases of a mailbox operationId: getTimeLimitedAliases description: >- The valid or permanent time-limited aliases of the mailbox. `{}` if none or no access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: List of aliases content: application/json: schema: type: array items: $ref: "#/components/schemas/TimeLimitedAlias" example: - address: kahd.osuwe@example.org goto: john.doe@example.org description: Online shop registration validity: 1795699200 created: "2026-11-10 09:00:00" modified: null permanent: 0 "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/time_limited_alias: post: tags: - Mailbox user settings summary: Update time-limited aliases operationId: editTimeLimitedAlias description: >- Sets a new expiry (`validity` hours from now) or makes the aliases permanent. Needs the user ACL `spam_alias`. Without `validity` or a true `permanent` nothing changes. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Alias address or list of addresses oneOf: - type: string - type: array items: type: string attr: type: object properties: validity: type: [integer, string] description: Hours from now until the alias expires (not range-checked); ends a permanent state permanent: type: [boolean, integer, string] description: true makes the alias permanent (wins over `validity`) example: items: - kahd.osuwe@example.org attr: validity: 24 permanent: 0 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/time_limited_alias: post: tags: - Mailbox user settings summary: Delete time-limited aliases operationId: deleteTimeLimitedAlias description: >- Deletes time-limited aliases. Needs the user ACL `spam_alias`. requestBody: required: true content: application/json: schema: type: array description: Alias addresses items: type: string example: - kahd.osuwe@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/pushover-test: post: tags: - Mailbox user settings summary: Verify the Pushover credentials of mailboxes operationId: testPushover description: >- Checks the stored Pushover credentials of each mailbox with the Pushover API; `attr` is not used. Same access as `edit/pushover`. Answers "Pushover API OK (200): ..." or "Pushover API ERR (code): ..."; a mailbox without settings stops the call. requestBody: required: true content: application/json: schema: type: object required: - items properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object description: Not used example: items: - john.doe@example.org attr: {} responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/delimiter_action: post: tags: - Mailbox user settings summary: Set the handling of tagged mail operationId: editDelimiterAction description: >- Handling of mail to `user+tag@example.org`: move to the subfolder "tag" (`subfolder`), add "[tag]" to the subject (`subject`) or nothing (`none`, also for other values). Needs the user ACL `delimiter_action`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object properties: tagged_mail_handler: type: string enum: - subfolder - subject - none example: items: - john.doe@example.org attr: tagged_mail_handler: subfolder responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/tls_policy: post: tags: - Mailbox user settings summary: Set the TLS policy of mailboxes operationId: editTlsPolicy description: >- Enforces TLS for incoming and/or outgoing mail; fields not sent keep their value. Needs the user ACL `tls_policy`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object properties: tls_enforce_in: type: [integer, string] enum: [0, 1, "0", "1"] description: 1 accepts incoming mail only over TLS tls_enforce_out: type: [integer, string] enum: [0, 1, "0", "1"] description: 1 sends outgoing mail only over TLS example: items: - john.doe@example.org attr: tls_enforce_in: 1 tls_enforce_out: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/spam-score: get: tags: - Mailbox user settings summary: Get the default spam score operationId: getDefaultSpamScore description: >- The spam thresholds of the session user; for API keys the Rspamd default (`5,15` if Rspamd is unreachable). responses: "200": description: Thresholds content: application/json: schema: $ref: "#/components/schemas/SpamScore" example: score: "8,15" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/api-key/{id}: get: summary: Get API key description: One API key with its value. A read-only API key gets `{}`. operationId: getApiKey tags: - API Keys parameters: - name: id in: path required: true description: ID of the API key schema: type: integer example: 3 responses: "200": description: The API key, `{}` if there is none with this ID or for a read-only API key content: application/json: schema: $ref: "#/components/schemas/ApiKey" example: id: 3 description: provisioning access: rw api_key: 1B7E2C-94F0A3-6D5B18-C2E7F4-03A9D6 allow_from: - 192.0.2.10 - 2001:db8::/64 skip_ip_check: 0 service: 0 active: 1 created: "2026-11-02 09:12:44" modified: "2026-11-05 16:40:02" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/api-key/all: get: summary: Get API keys description: >- Lists all API keys with their values, service keys first. A read-only API key gets `{}`. operationId: getApiKeys tags: - API Keys responses: "200": description: The API keys, `{}` if there are none or for a read-only API key content: application/json: schema: type: array items: $ref: "#/components/schemas/ApiKey" example: - id: 1 description: API_KEY access: rw api_key: 8F2D41-0C9A7B-5E3F12-AB46C0-77D1E9 allow_from: - 192.0.2.0/24 skip_ip_check: 0 service: 1 active: 1 created: "2026-09-21 10:20:00" modified: null - id: 3 description: provisioning access: rw api_key: 1B7E2C-94F0A3-6D5B18-C2E7F4-03A9D6 allow_from: - 192.0.2.10 - 2001:db8::/64 skip_ip_check: 0 service: 0 active: 1 created: "2026-11-02 09:12:44" modified: "2026-11-05 16:40:02" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/app-passwd/all/{mailbox}: get: tags: - App Passwords summary: Get the app passwords of a mailbox operationId: getAppPasswords description: >- The app passwords of the mailbox, with password hashes. `{}` if none or no access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: List of app passwords content: application/json: schema: type: array items: $ref: "#/components/schemas/AppPassword" example: - id: 23 name: Thunderbird mailbox: john.doe@example.org domain: example.org password: "{BLF-CRYPT}$2y$10$..." created: "2026-11-08 20:38:01" modified: null imap_access: 1 smtp_access: 1 dav_access: 0 eas_access: 0 pop3_access: 0 sieve_access: 1 active: 1 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/app-passwd/all: get: tags: - App Passwords summary: Get the app passwords of the logged-in mailbox operationId: getOwnAppPasswords description: >- The app passwords of the logged-in mailbox user. API keys get `{}`; use `get/app-passwd/all/{mailbox}`. responses: "200": description: List of app passwords content: application/json: schema: type: array items: $ref: "#/components/schemas/AppPassword" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/app-passwd/{id}: get: tags: - App Passwords summary: Get an app password (broken) operationId: getAppPassword description: >- Broken: always ends with an error and an empty body. Use `get/app-passwd/all/{mailbox}`. parameters: - name: id in: path required: true description: App password ID schema: type: integer example: 23 responses: "200": description: Empty body "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/app-passwd: post: tags: - App Passwords summary: Update app passwords operationId: editAppPassword description: >- Changes app passwords by ID; fields not sent keep their value. Needs the user ACL `app_passwds`. Messages: `object_modified`; errors `app_passwd_id_invalid`, `password_complexity`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: App password ID or list of IDs oneOf: - type: integer - type: array items: type: integer attr: type: object properties: username: type: string description: Mailbox the app passwords belong to (required for API keys) app_name: type: string app_passwd: type: string format: password description: New password; changed only together with `app_passwd2` app_passwd2: type: string format: password protocols: description: Replaces the allowed protocols type: array items: type: string enum: - imap_access - smtp_access - pop3_access - sieve_access - dav_access - eas_access active: type: [integer, string] enum: [0, 1, "0", "1"] example: items: - 23 attr: username: john.doe@example.org active: 0 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/bcc/{id}: get: tags: - Address Rewriting summary: Get BCC maps operationId: getBccMaps description: >- `all` lists the BCC maps of the domains the caller manages, an ID returns one map with an extra member `"0": null`. `{}` if there is none. parameters: - name: id in: path required: true description: "`all` or the ID of a BCC map" schema: type: string example: all responses: "200": description: The list of BCC maps (`all`) or one BCC map content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/BccMap" - $ref: "#/components/schemas/BccMap" examples: all: summary: get/bcc/all value: - id: 3 local_dest: "@example.org" bcc_dest: archive@example.com active: 1 type: rcpt created: "2026-11-03 10:15:22" domain: example.org modified: null one: summary: get/bcc/3 value: id: 3 local_dest: "@example.org" bcc_dest: archive@example.com active: 1 type: rcpt created: "2026-11-03 10:15:22" domain: example.org modified: null "0": null "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/dkim/{domain}: get: summary: Get the DKIM key of a domain description: >- The DKIM public key of a domain or alias domain and the TXT record for `._domainkey.`. `privkey` is empty unless `SHOW_DKIM_PRIV_KEYS` is enabled. operationId: getDkimKey tags: - DKIM parameters: - name: domain in: path required: true description: Domain or alias domain name schema: type: string example: example.org responses: "200": description: The DKIM key content: application/json: schema: $ref: "#/components/schemas/DkimKey" example: pubkey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxV3...IDAQAB length: "2048" dkim_txt: v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxV3...IDAQAB dkim_selector: dkim privkey: "" "401": $ref: "#/components/responses/Unauthorized" /api/v1/add/dkim_import: post: summary: Import a DKIM key description: >- Imports an RSA private key as the DKIM key of a domain, which need not exist in mailcow. Success answers `dkim_removed` and `dkim_added`. Messages: errors `private_key_error`, `dkim_domain_or_sel_exists`. operationId: importDkimKey tags: - DKIM requestBody: required: true content: application/json: schema: type: object required: - domain - private_key_file properties: domain: type: string description: Domain name dkim_selector: type: string default: dkim description: Selector (letters, digits, `-`, `_`, `.`) private_key_file: type: string description: The private key in PEM format (the text, not a file upload) overwrite_existing: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: Replace an existing key of the domain example: domain: example.org dkim_selector: dkim2026 private_key_file: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC...\n-----END PRIVATE KEY-----" overwrite_existing: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/domain-admin/all: get: summary: Get domain administrators description: Lists all domain administrators. operationId: getDomainAdmins tags: - Domain admin responses: "200": description: The domain administrators, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/DomainAdmin" example: - username: domainadmin1 tfa_active: 0 tfa_active_int: 0 active: 1 active_int: 1 created: "2026-09-21 10:24:48" attributes: force_tfa: "0" force_pw_update: "0" selected_domains: - example.org unselected_domains: - example.com "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/domain-admin/{username}: get: summary: Get domain administrator description: Details of one domain administrator. operationId: getDomainAdmin tags: - Domain admin parameters: - name: username in: path required: true description: Username of the domain administrator schema: type: string example: domainadmin1 responses: "200": description: The domain administrator, `{}` if there is none of this name content: application/json: schema: $ref: "#/components/schemas/DomainAdmin" example: username: domainadmin1 tfa_active: 0 tfa_active_int: 0 active: 1 active_int: 1 created: "2026-09-21 10:24:48" attributes: force_tfa: "0" force_pw_update: "0" selected_domains: - example.org - example.com unselected_domains: "" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/domain/{id}: get: summary: Get domains description: >- `all` lists all domains (`{}` if none), a domain name returns that domain, an alias domain name its target. Domain admins see only their domains. Quotas are in bytes. operationId: getDomains tags: - Domains parameters: - name: id in: path required: true description: "`all` or a domain name" schema: type: string example: all - name: tags in: query required: false description: >- Only with `all`: comma-separated tag names, answers only the domains with a tag that contains one of them schema: type: string example: customer,premium responses: "200": description: The list of domains (`all`) or one domain content: application/json: schema: oneOf: - type: array items: $ref: "#/components/schemas/Domain" - $ref: "#/components/schemas/Domain" example: - max_new_mailbox_quota: 10632560640 def_new_mailbox_quota: 3221225472 quota_used_in_domain: "104857600" bytes_total: "79324302" msgs_total: "132" mboxes_in_domain: 3 mboxes_left: 7 domain_name: example.org domain_h_name: example.org description: Example Org max_num_aliases_for_domain: 400 max_num_mboxes_for_domain: 10 def_quota_for_mbox: 3221225472 max_quota_for_mbox: 10737418240 max_quota_for_domain: 10737418240 relayhost: "0" backupmx: 0 backupmx_int: 0 gal: 1 gal_int: 1 rl: value: "100" frame: h active: 1 active_int: 1 relay_all_recipients: 0 relay_all_recipients_int: 0 relay_unknown_only: 0 relay_unknown_only_int: 0 created: "2026-09-21 10:24:34" modified: "2026-11-06 18:15:08" aliases_in_domain: 1 aliases_left: 399 domain_admins: anna.admin tags: - customer "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/domain/template/{id}: get: summary: Get domain templates description: >- `all` lists the domain templates, an ID returns that template. Domain admins may call it too. Quotas are in bytes. operationId: getDomainTemplates tags: - Domains parameters: - name: id in: path required: true description: "`all` or a template ID" schema: type: string example: all responses: "200": description: The list of templates (`all`) or one template content: application/json: schema: oneOf: - type: array items: $ref: "#/components/schemas/DomainTemplate" - $ref: "#/components/schemas/DomainTemplate" example: - id: 1 template: Default type: domain attributes: tags: [] max_num_aliases_for_domain: 400 max_num_mboxes_for_domain: 10 def_quota_for_mbox: 3221225472 max_quota_for_mbox: 10737418240 max_quota_for_domain: 10737418240 rl_frame: s rl_value: "" active: 1 gal: 1 backupmx: 0 relay_all_recipients: 0 relay_unknown_only: 0 dkim_selector: dkim key_size: 2048 created: "2026-09-21 10:23:08" modified: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/add/domain/template: post: summary: Add a domain template description: >- Adds a domain template (defaults for new domains). Quotas are sent in MiB, returned in bytes. Fields not sent, and numbers and quotas sent as 0, get the defaults shown. Messages: `template_added`; errors `template_name_invalid`, `template_exists`. operationId: addDomainTemplate tags: - Domains requestBody: required: true content: application/json: schema: allOf: - $ref: "#/components/schemas/DomainTemplateInput" - required: - template example: template: Small business max_num_aliases_for_domain: 400 max_num_mboxes_for_domain: 25 def_quota_for_mbox: 2048 max_quota_for_mbox: 5120 max_quota_for_domain: 51200 rl_value: 500 rl_frame: h active: 1 gal: 1 backupmx: 0 relay_all_recipients: 0 relay_unknown_only: 0 dkim_selector: dkim key_size: 2048 tags: - small responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/domain/template: post: summary: Edit domain templates description: >- Replaces domain templates. Fields not sent are reset: numbers and quotas to 0, the rest to the defaults shown. Edit one template per call, with several IDs all get the first one's name. Always answers `template_modified`, also for unknown IDs. operationId: editDomainTemplate tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Template ID or list of template IDs oneOf: - type: [integer, string] - type: array items: type: [integer, string] attr: $ref: "#/components/schemas/DomainTemplateInput" example: items: - 2 attr: template: Small business max_num_aliases_for_domain: 400 max_num_mboxes_for_domain: 50 def_quota_for_mbox: 2048 max_quota_for_mbox: 5120 max_quota_for_domain: 102400 rl_value: 500 rl_frame: h active: 1 gal: 1 backupmx: 0 relay_all_recipients: 0 relay_unknown_only: 0 dkim_selector: dkim key_size: 2048 tags: - small responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/domain/template: post: summary: Delete a domain template description: >- Deletes a domain template; only the first ID of the list is used. The `Default` template cannot be deleted. Always answers `template_removed`. operationId: deleteDomainTemplate tags: - Domains requestBody: required: true content: application/json: schema: type: array description: Template IDs (only the first is used) items: type: [integer, string] example: - 2 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/search/domain: post: summary: Search domains (table of the UI) description: >- Paging, sorting and searching for the DataTables domain table of the UI. Read-only API keys may use it, domain admins see only their domains. Positions in `columns` and `order[].column`: 2 domain name, 3 aliases, 4 mailboxes, 5 domain quota, 6 storage (sort only), 7 default mailbox quota, 8 max. mailbox quota, 10 relay domain, 14 tags (global search only), 15 active; others mean the domain name. `columns` is required with `search.value`. Without `Content-Type: application/json` all domains are returned. SQL errors answer `{"error": "..."}` with status 200. operationId: searchDomains tags: - Domains requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DomainSearchRequest" example: draw: 1 start: 0 length: 10 search: value: example order: - column: 2 dir: asc columns: - data: "" searchable: false orderable: false - data: chkbox searchable: false orderable: false - data: domain_h_name searchable: true orderable: true search: value: "" responses: "200": description: One page of domains, with the counts DataTables needs content: application/json: schema: $ref: "#/components/schemas/DomainSearchResult" example: draw: 1 recordsTotal: 12 recordsFiltered: 1 data: - max_new_mailbox_quota: 10632560640 def_new_mailbox_quota: 3221225472 quota_used_in_domain: "104857600" bytes_total: "79324302" msgs_total: "132" mboxes_in_domain: 3 mboxes_left: 7 domain_name: example.org domain_h_name: example.org description: Example Org max_num_aliases_for_domain: 400 max_num_mboxes_for_domain: 10 def_quota_for_mbox: 3221225472 max_quota_for_mbox: 10737418240 max_quota_for_domain: 10737418240 relayhost: "0" backupmx: 0 backupmx_int: 0 gal: 1 gal_int: 1 rl: false active: 1 active_int: 1 relay_all_recipients: 0 relay_all_recipients_int: 0 relay_unknown_only: 0 relay_unknown_only_int: 0 created: "2026-09-21 10:24:34" modified: "2026-11-06 18:15:08" aliases_in_domain: 1 aliases_left: 399 domain_admins: "-" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/alias-domain/{id}: get: summary: Get alias domains description: >- `all` lists all alias domains, a name returns that alias domain. Domain admins see only those of their domains. operationId: getAliasDomains tags: - Domains parameters: - name: id in: path required: true description: "`all` or an alias domain name" schema: type: string example: all responses: "200": description: The list of alias domains (`all`) or one alias domain content: application/json: schema: oneOf: - type: array items: $ref: "#/components/schemas/AliasDomain" - $ref: "#/components/schemas/AliasDomain" example: - alias_domain: example.net parent_is_backupmx: 0 target_domain: example.org active: 1 active_int: 1 rl: false created: "2026-10-02 08:12:45" modified: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/add/alias-domain: post: summary: Add alias domains description: >- Adds alias domains: mail goes to the same local part in the target domain, which must be accessible and no relay domain. Needs the ACL `alias_domains`. Can also set the rate limit and create a DKIM key. An invalid name ends the call without an answer. Messages: `aliasd_added`; errors `alias_domain_invalid`, `targetd_not_found`, `targetd_relay_domain`. operationId: addAliasDomain tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - alias_domain - target_domain properties: alias_domain: type: string description: >- Alias domain name; several are separated by spaces, commas, semicolons or line breaks target_domain: type: string description: The domain the alias domain points to active: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: Alias domain active (inactive when not sent) rl_value: type: [integer, string] description: Rate limit, messages per `rl_frame`; empty or 0 = none rl_frame: type: string enum: [s, m, h, d] description: Rate limit time frame dkim_selector: type: string description: Selector of the DKIM key that is created key_size: type: [integer, string] description: >- RSA size of the new DKIM key in bits; a key needs `key_size` and `dkim_selector` example: alias_domain: example.net target_domain: example.org active: 1 rl_value: 100 rl_frame: h dkim_selector: dkim key_size: 2048 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/alias-domain: post: summary: Edit alias domains description: >- Changes alias domains; fields not sent keep their value. The new target must be an accessible domain, not an alias domain. Messages: `aliasd_modified`; errors `alias_domain_invalid`, `target_domain_invalid`. operationId: editAliasDomain tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Alias domain name or list of alias domain names oneOf: - type: string - type: array items: type: string attr: type: object properties: active: type: [integer, string] enum: [0, 1, "0", "1"] description: Alias domain active target_domain: type: string description: New target domain example: items: - example.net attr: active: 1 target_domain: example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/alias-domain: post: summary: Delete alias domains description: >- Deletes alias domains with their aliases, spam aliases and BCC maps. The rate limit is kept. Messages: `alias_domain_removed`; error `domain_invalid`. operationId: deleteAliasDomain tags: - Domains requestBody: required: true content: application/json: schema: type: array description: Alias domain names items: type: string example: - example.net responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/mta-sts: post: summary: Add an MTA-STS policy description: >- Adds the MTA-STS policy of a domain, published when active at `https://mta-sts./.well-known/mta-sts.txt`. The `_mta-sts` TXT record ID is the change time (`YYYYMMDDhhmmss`). Policies of alias domains are never published, they use their target's. A second policy fails with a database error. There is no read route. Messages: errors `version_invalid`, `mode_invalid`, `max_age_invalid`, `mx_invalid`. operationId: addMtaSts tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - domain - version - mode - mx - max_age properties: domain: type: string description: Domain or alias domain version: type: string enum: [stsv1, STSv1] description: Policy version (case-insensitive) mode: type: string enum: [enforce, testing, none] description: >- `enforce` rejects delivery without valid TLS, `testing` only reports, `none` publishes without effect mx: type: string description: Comma-separated MX host names, wildcards like `*.example.org` allowed max_age: type: [integer, string] description: Seconds senders may cache the policy, 1 to 31536000 active: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: Policy published (inactive when not sent) example: domain: example.org version: stsv1 mode: enforce mx: mail.example.org,mx2.example.org max_age: 86400 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/mta-sts: post: summary: Edit MTA-STS policies description: >- Changes MTA-STS policies; fields not sent keep their value, but `version` is required. Changing `version`, `mode`, `mx` or `max_age` gives a new policy ID. A domain without policy answers `access_denied`. Messages: `object_modified`; errors `version_invalid`, `mode_invalid`, `mx_invalid`. operationId: editMtaSts tags: - Domains requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Domain name or list of domain names oneOf: - type: string - type: array items: type: string attr: type: object required: - version properties: version: type: string enum: [stsv1, STSv1] description: Policy version mode: type: string enum: [enforce, testing, none] description: Policy mode mx: type: string description: Comma-separated MX host names max_age: type: [integer, string] description: Seconds senders may cache the policy, 1 to 31557600 active: type: [integer, string] enum: [0, 1, "0", "1"] description: Policy published example: items: - example.org attr: version: stsv1 mode: testing mx: mail.example.org max_age: 604800 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/fail2ban: get: summary: Get Fail2Ban settings and bans description: >- Returns the Fail2Ban settings, regex filters, allow- and denylists and the current bans. operationId: getFail2Ban tags: - Fail2Ban responses: "200": description: Settings and bans content: application/json: schema: $ref: "#/components/schemas/Fail2Ban" example: ban_time: 1800 ban_time_increment: true max_ban_time: 86400 netban_ipv4: 32 netban_ipv6: 128 max_attempts: 10 retry_window: 600 banlist_id: a2c11baf-5770-47de-9c5e-575bd7bc9218 manage_external: 0 regex: "1": "^mailcow UI: Invalid password for .+ by ([0-9a-f\\.:]+)$" "2": "^Rspamd UI: Invalid password by ([0-9a-f\\.:]+)$" whitelist: |- 192.0.2.0/24 mail.example.org blacklist: 198.51.100.66/32 perm_bans: - network: 198.51.100.66/32 ip: 198.51.100.66 active_bans: - queued_for_unban: 0 network: 203.0.113.7/32 ip: 203.0.113.7 banned_until: 00h 27m 08s "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/fail2ban/banlist: post: summary: Renew the Fail2Ban banlist URL description: >- Gives the banlist URL `/f2b-banlist?id=` a new random ID; the old URL stops working. `items` must hold the current `banlist_id`, else the status is 404. A Redis error gives status 500. Messages: `f2b_banlist_refreshed`; errors `redis_error`. operationId: refreshFail2BanBanlist tags: - Fail2Ban requestBody: content: application/json: schema: type: object properties: items: description: The current banlist ID (single value or a list with it as first element) oneOf: - type: array items: type: string - type: string attr: type: object description: Not used required: - items example: items: - a2c11baf-5770-47de-9c5e-575bd7bc9218 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": description: "`items` does not hold the current banlist ID" content: application/json: schema: $ref: "#/components/schemas/TaskResult" example: type: error msg: Cannot edit item /api/v1/get/logs/acme/{count}: get: summary: Get ACME logs (count or range) description: Entries of the ACME (Let's Encrypt) log, newest first. operationId: getAcmeLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/AcmeLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/api/{count}: get: summary: Get API logs (count or range) description: API requests with their data (secrets replaced by `*`), newest first. operationId: getApiLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/ApiLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/autodiscover/{count}: get: summary: Get Autodiscover logs (count or range) description: Autodiscover requests (Outlook, ActiveSync) with the offered service, newest first. operationId: getAutodiscoverLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/AutodiscoverLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/dovecot/{count}: get: summary: Get Dovecot logs (count or range) description: Entries of the Dovecot log (IMAP, POP3, Sieve, LMTP), newest first. operationId: getDovecotLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/DovecotLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/netfilter/{count}: get: summary: Get netfilter logs (count or range) description: Entries of netfilter (failed logins, bans), newest first. operationId: getNetfilterLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/NetfilterLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/postfix/{count}: get: summary: Get Postfix logs (count or range) description: Entries of the Postfix log (SMTP), newest first. operationId: getPostfixLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/PostfixLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/ratelimited/{count}: get: summary: Get rate limit logs (count or range) description: Messages rejected by a rate limit, newest first. operationId: getRatelimitLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/RatelimitLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/rspamd-history/{count}: get: summary: Get Rspamd history (count or range) description: Messages scanned by Rspamd, newest first. operationId: getRspamdHistoryByCount tags: - Logs parameters: - name: count in: path required: true description: >- `N`: the newest N messages; `from-to` (from ≥ 1) counts from 0, so `2-3` gives the third and fourth newest schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/RspamdHistory" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/sogo/{count}: get: summary: Get SOGo logs (count or range) description: Entries of the SOGo log, newest first. operationId: getSogoLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/SogoLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/watchdog/{count}: get: summary: Get watchdog logs (count or range) description: Watchdog health checks, newest first. operationId: getWatchdogLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/WatchdogLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/acme: get: summary: Get ACME logs description: The newest 1000 entries of the ACME (Let's Encrypt) log, newest first. operationId: getAcmeLogs tags: - Logs responses: "200": $ref: "#/components/responses/AcmeLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/api: get: summary: Get API logs description: >- The newest 1000 API requests with their data (secrets replaced by `*`), newest first. operationId: getApiLogs tags: - Logs responses: "200": $ref: "#/components/responses/ApiLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/autodiscover: get: summary: Get Autodiscover logs description: >- The newest 1000 Autodiscover requests (Outlook, ActiveSync) with the offered service, newest first. operationId: getAutodiscoverLogs tags: - Logs responses: "200": $ref: "#/components/responses/AutodiscoverLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/cron: get: summary: Get cron logs description: >- The newest 1000 entries of the mailcow scheduled tasks (identity provider sync, group shares, ...), newest first. operationId: getCronLogs tags: - Logs responses: "200": $ref: "#/components/responses/CronLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/cron/{count}: get: summary: Get cron logs (count or range) description: Entries of the mailcow scheduled tasks, newest first. operationId: getCronLogsByCount tags: - Logs parameters: - name: count in: path required: true description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)" schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/CronLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/dovecot: get: summary: Get Dovecot logs description: The newest 1000 entries of the Dovecot log (IMAP, POP3, Sieve, LMTP), newest first. operationId: getDovecotLogs tags: - Logs responses: "200": $ref: "#/components/responses/DovecotLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/netfilter: get: summary: Get netfilter logs description: The newest 1000 entries of netfilter (failed logins, bans), newest first. operationId: getNetfilterLogs tags: - Logs responses: "200": $ref: "#/components/responses/NetfilterLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/postfix: get: summary: Get Postfix logs description: The newest 1000 entries of the Postfix log (SMTP), newest first. operationId: getPostfixLogs tags: - Logs responses: "200": $ref: "#/components/responses/PostfixLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/ratelimited: get: summary: Get rate limit logs description: The newest 1000 messages rejected by a rate limit, newest first. operationId: getRatelimitLogs tags: - Logs responses: "200": $ref: "#/components/responses/RatelimitLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/rspamd-history: get: summary: Get Rspamd history description: The newest 1000 messages scanned by Rspamd, newest first. operationId: getRspamdHistory tags: - Logs responses: "200": $ref: "#/components/responses/RspamdHistory" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/rspamd-stats: get: summary: Get Rspamd statistics description: Rspamd statistics (scanned and learned messages, actions, Bayes). operationId: getRspamdStats tags: - Logs responses: "200": description: The statistics, `{}` if Rspamd cannot be reached content: application/json: schema: $ref: "#/components/schemas/RspamdStats" example: version: 3.12.1 config_id: ch8ha1o68oxb3xf9izngisz4wxuxgs86n9gg6yko7jtt4msu4bxhuunnoi4pk7an4y5htzjb1y9nwsxmkjhdu671ocb5b5ea1g38csb uptime: 25891 read_only: false scanned: 300 learned: 30 actions: reject: 38 soft reject: 0 rewrite subject: 0 add header: 6 greylist: 1 no action: 255 scan_times: - 0.340365 - 0.48114 spam_count: 44 ham_count: 256 connections: 24 control_connections: 700 total_learns: 29 statfiles: - revision: 6 users: 1 used: 0 total: 0 size: 0 symbol: BAYES_SPAM type: redis languages: 0 class: spam fuzzy_hashes: mailcow: 0 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/sasl: get: summary: Get SASL logs description: >- The newest 1000 successful logins (IMAP, POP3, SMTP, SOGo, ...), one entry per service, address and user, newest first. operationId: getSaslLogs tags: - Logs responses: "200": $ref: "#/components/responses/SaslLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/sasl/{count}: get: summary: Get SASL logs (count or range) description: >- Successful logins, one entry per service, address and user, newest first. operationId: getSaslLogsByCount tags: - Logs parameters: - name: count in: path required: true description: >- `N`: the newest N entries; `from-to`: `to` entries starting at `from` (newest = 1), so `2-3` gives entries 2 to 4 schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/SaslLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/sogo: get: summary: Get SOGo logs description: The newest 1000 entries of the SOGo log, newest first. operationId: getSogoLogs tags: - Logs responses: "200": $ref: "#/components/responses/SogoLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/ui: get: summary: Get mailcow UI logs description: The newest 1000 messages of UI and API calls, newest first. operationId: getUiLogs tags: - Logs responses: "200": $ref: "#/components/responses/UiLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/ui/{count}: get: summary: Get mailcow UI logs (count or range) description: Messages of UI and API calls, newest first. operationId: getUiLogsByCount tags: - Logs parameters: - name: count in: path required: true description: >- `N`: the newest N entries; `from-to`: `to` entries starting at `from` (newest = 1), so `2-3` gives entries 2 to 4 schema: type: string pattern: ^[0-9]+(-[0-9]+)?$ example: "50" responses: "200": $ref: "#/components/responses/UiLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/logs/watchdog: get: summary: Get watchdog logs description: The newest 1000 watchdog health checks, newest first. operationId: getWatchdogLogs tags: - Logs responses: "200": $ref: "#/components/responses/WatchdogLogs" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox/{id}: get: tags: - Mailboxes summary: Get a mailbox operationId: getMailbox description: >- One mailbox, `{}` if not found or no access. A mailbox user may read its own. With `tags`, `{id}` is a search term: the answer lists the mailboxes whose address contains `{id}` and that have a matching tag. parameters: - name: id in: path required: true description: "Mailbox address (with `tags`: part of the address, e.g. a domain)" schema: type: string example: john.doe@example.org - $ref: "#/components/parameters/MailboxTagsQuery" responses: "200": description: The mailbox; with `tags` a list of mailboxes content: application/json: schema: oneOf: - $ref: "#/components/schemas/Mailbox" - type: array items: $ref: "#/components/schemas/Mailbox" examples: mailbox: $ref: "#/components/examples/MailboxDetails" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox-group/{id}: get: summary: Get mailbox group description: >- One group by id, visible as in `GET /api/v1/get/mailbox-group/all`. operationId: getMailboxGroup tags: - Groups parameters: - name: id in: path required: true description: Group id schema: type: integer example: 7 responses: "200": description: The group content: application/json: schema: $ref: "#/components/schemas/MailboxGroup" example: id: 7 domain: example.org name: Sales description: Sales team address: sales@example.org sender_allowed: 1 sogo_visible: 0 internal: 1 template_id: 3 template: Staff priority: 10 idp_ref: null members: - username: alice@example.org source: manual send_as: - "@example.com" imap_grants: [] sogo_grants: [] active: 1 created: "2026-10-25 12:00:00" modified: null can_edit: true "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox-group/member/{username}: get: summary: Get group memberships of a mailbox description: >- The groups of a mailbox with its effective template and send-as addresses. Domain admins with the `mailbox_groups` ACL may read their mailboxes and see only groups of their domains; users may read their own. operationId: getMailboxGroupMemberships tags: - Groups parameters: - name: username in: path required: true description: Mailbox (case-insensitive) schema: type: string example: alice@example.org responses: "200": description: The memberships content: application/json: schema: $ref: "#/components/schemas/MailboxGroupMemberships" example: groups: - id: 7 domain: example.org name: Sales address: sales@example.org sender_allowed: 1 active: 1 priority: 10 template: Staff source: manual template: Staff send_as: - orders@example.org - sales@example.org "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox-group/all: get: summary: Get mailbox groups description: >- All groups the caller may see, ordered by domain and name. Domain admins with the `mailbox_groups` ACL get the groups of their domains. operationId: getMailboxGroups tags: - Groups responses: "200": description: The groups content: application/json: schema: type: array items: $ref: "#/components/schemas/MailboxGroup" example: - id: 7 domain: example.org name: Sales description: Sales team address: sales@example.org sender_allowed: 1 sogo_visible: 0 internal: 0 template_id: 3 template: Staff priority: 10 idp_ref: null members: - username: alice@example.org source: manual - username: bob@example.org source: idp send_as: - orders@example.org imap_grants: - owner: shared@example.org rights: write subscribe: 1 state: applied last_error: null sogo_grants: - owner: shared@example.org type: Calendar folder: personal access: read subscribe: 0 state: pending last_error: null active: 1 created: "2026-10-25 12:00:00" modified: "2026-10-28 09:14:03" can_edit: true "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox-group/all/{domains}: get: summary: Get mailbox groups of domains description: >- Like `GET /api/v1/get/mailbox-group/all`, limited to the given domains. operationId: getMailboxGroupsOfDomains tags: - Groups parameters: - name: domains in: path required: true description: One domain or a comma-separated list of domains schema: type: string example: example.org,example.com responses: "200": description: The groups of the domains content: application/json: schema: type: array items: $ref: "#/components/schemas/MailboxGroup" example: - id: 7 domain: example.org name: Sales description: "" address: sales@example.org sender_allowed: 1 sogo_visible: 1 internal: 0 template_id: null template: null priority: 0 idp_ref: null members: - username: alice@example.org source: manual send_as: [] imap_grants: [] sogo_grants: [] active: 1 created: "2026-10-25 12:00:00" modified: null can_edit: true "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/identity-provider/sync-status: get: summary: Get identity sync status description: >- Status of the identity sync: provider, mailbox counts and the last 10 runs. Runs with status `blocked` (stopped by `offboarding_limit`) or `error` changed nothing. operationId: getIdentitySyncStatus tags: - Identity Provider responses: "200": description: The sync status content: application/json: schema: $ref: "#/components/schemas/IdentitySyncStatus" example: provider: keycloak can_sync: true sync_enabled: true counts: accounts: 120 linked: 118 idp_disabled: 2 missing: 1 runs: - id: 42 provider: keycloak mode: run status: ok requested_by: "" created: "2026-11-09 12:00:00" started: "2026-11-09 12:00:01" finished: "2026-11-09 12:00:03" summary: counts: links: 0 creates: 1 deactivate: 1 restore: 0 release: 0 missing: 1 found: 0 updates: 3 group_creates: 0 group_renames: 0 memberships: 2 orphaned_groups: 0 conflicts: 0 membership_removals: 0 skipped: 0 errors: 0 details: creates: - new.user@example.org deactivate: - left.user@example.org restore: [] missing: - left.user@example.org group_creates: [] conflicts: [] blocked: false errors: [] mode: run "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/identity-link/{username}: get: summary: Get identity link of a mailbox description: >- The Identity Provider user a mailbox is linked to. Domain admins may read their mailboxes. A never linked mailbox that the sync misses at the provider has `missing_since` but no `external_id`. operationId: getIdentityLink tags: - Identity Provider parameters: - name: username in: path required: true description: Mailbox (case-insensitive) schema: type: string example: alice@example.org responses: "200": description: The link content: application/json: schema: $ref: "#/components/schemas/IdentityLink" example: provider: keycloak external_id: 8d5da28d-7541-428b-8356-a9704f73e7f4 idp_disabled: 0 missing_since: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailq/all: get: summary: Get the mail queue description: >- Returns the Postfix mail queue, at most 10000 entries. operationId: getMailQueue tags: - Queue Manager responses: "200": description: List of queued messages content: application/json: schema: type: array items: $ref: "#/components/schemas/MailQueueItem" example: - queue_name: deferred queue_id: B98C6260CA1 arrival_time: 1762768034 message_size: 1848 forced_expire: false sender: sender@example.org recipients: - "rcpt@example.com (connect to mx.example.com[192.0.2.25]:25: Connection timed out)" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/postcat/{qid}: get: summary: Get a queued message description: >- Returns a queued message as postcat prints it: envelope, headers and body. The answer is plain text despite the JSON content type. An unknown queue ID gives the error text of postcat. operationId: getQueuedMessage tags: - Queue Manager parameters: - name: qid in: path required: true description: Postfix queue ID schema: type: string example: B98C6260CA1 responses: "200": description: The postcat output as plain text (despite the JSON content type) content: application/json: schema: type: string example: | *** ENVELOPE RECORDS deferred/B/B98C6260CA1 *** message_size: 1848 612 1 0 1848 0 message_arrival_time: Mon Nov 10 09:47:14 2026 create_time: Mon Nov 10 09:47:14 2026 named_attribute: rewrite_context=local sender: sender@example.org *** MESSAGE CONTENTS deferred/B/B98C6260CA1 *** From: Sender To: rcpt@example.com Subject: Test Hello *** HEADER EXTRACTED deferred/B/B98C6260CA1 *** original_recipient: rcpt@example.com recipient: rcpt@example.com *** MESSAGE FILE END deferred/B/B98C6260CA1 *** "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/oauth2-client/{id}: get: summary: Get OAuth2 client description: One OAuth2 client with its secret. operationId: getOAuth2Client tags: - oAuth Clients parameters: - name: id in: path required: true description: ID of the client (`id`, not `client_id`) schema: type: integer example: 1 responses: "200": description: The client, `{}` if there is none with this ID content: application/json: schema: $ref: "#/components/schemas/OAuth2Client" example: id: 1 client_id: 17c76aaa88c0 client_secret: 73fc668a88147e32a31ff80c redirect_uri: https://app.example.org/oauth/callback grant_types: null scope: profile user_id: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/oauth2-client/all: get: summary: Get OAuth2 clients description: >- Lists the clients of the mailcow OAuth2 server with their secrets. operationId: getOAuth2Clients tags: - oAuth Clients responses: "200": description: The clients, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/OAuth2Client" example: - id: 1 client_id: 17c76aaa88c0 client_secret: 73fc668a88147e32a31ff80c redirect_uri: https://app.example.org/oauth/callback grant_types: null scope: profile user_id: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/oauth2-client: post: summary: Edit OAuth2 clients description: >- Per client, `revoke_tokens` deletes its tokens, else `renew_secret` sets a new secret, else `redirect_uri` is changed. The first two act whenever present, even with value 0. Messages: `object_modified`; error `Redirect/Callback URL cannot be empty`. operationId: editOAuth2Client tags: - oAuth Clients requestBody: required: true content: application/json: schema: type: object properties: items: description: ID of the client, or a list of IDs oneOf: - type: [integer, string] - type: array items: type: [integer, string] attr: type: object properties: redirect_uri: type: string description: New redirect URL; empty or missing keeps the current one revoke_tokens: type: [integer, string, boolean] description: Present = delete the access and refresh tokens of the client renew_secret: type: [integer, string, boolean] description: Present = generate a new client secret required: - items - attr example: items: - 1 attr: redirect_uri: https://app.example.org/oauth/callback2 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/policy_bl_domain/{domain}: get: summary: Get the sender deny list of a domain description: >- The deny list (blacklist) entries of the domain and all its mailboxes; `object` tells which. operationId: getDomainBlacklist tags: - Domain antispam policies parameters: - name: domain in: path required: true description: Domain name schema: type: string example: example.org responses: "200": description: The deny list entries content: application/json: schema: type: array items: $ref: "#/components/schemas/DomainPolicyEntry" example: - object: example.org value: "*@spam.example.com" prefid: 13 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/policy_wl_domain/{domain}: get: summary: Get the sender allow list of a domain description: >- The allow list (whitelist) entries of the domain and all its mailboxes; `object` tells which. operationId: getDomainWhitelist tags: - Domain antispam policies parameters: - name: domain in: path required: true description: Domain name schema: type: string example: example.org responses: "200": description: The allow list entries content: application/json: schema: type: array items: $ref: "#/components/schemas/DomainPolicyEntry" example: - object: example.org value: "*@partner.example.com" prefid: 12 - object: anna@example.org value: newsletter@example.net prefid: 15 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/quarantine/all: get: summary: Get quarantined messages description: >- Returns the quarantined messages without content. Admins get every item, domain admins those of their domains, mailbox users their own. operationId: getQuarantine tags: - Quarantine responses: "200": description: List of quarantine items content: application/json: schema: type: array items: $ref: "#/components/schemas/QuarantineItem" example: - id: 33 qid: 8224615004C1 subject: You have won virus_flag: 0 score: 15.48 rcpt: john.doe@example.org sender: bounces@send.example.com action: reject created: 1762768034 notified: 1 "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/quarantine_category: post: tags: - Quarantine summary: Set the quarantine notification category of mailboxes operationId: editQuarantineCategory description: >- Which quarantined mail the notifications list: rejected (`reject`), sent to junk (`add_header`) or both (`all`). Needs the user ACL `quarantine_category`; a mailbox user may change only its own. An invalid value answers `access_denied`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object required: - quarantine_category properties: quarantine_category: type: string enum: - reject - add_header - all example: items: - john.doe@example.org attr: quarantine_category: all responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/quarantine/{id}: get: summary: Get a quarantined message description: >- Returns one quarantine item with the raw message and the Rspamd symbols. Domain admins and mailbox users only get their own items. `[]` for an unknown ID. operationId: getQuarantineItem tags: - Quarantine parameters: - name: id in: path required: true description: ID of the quarantine item schema: type: string example: "33" responses: "200": description: The quarantine item content: application/json: schema: $ref: "#/components/schemas/QuarantineItemDetails" example: id: 33 qid: 8224615004C1 subject: You have won score: 15.48 ip: 198.51.100.23 action: reject symbols: '[{"name":"BAYES_SPAM","score":5.1,"options":["99.99%"]},{"name":"RBL_SPAMHAUS_SBL","score":4.0}]' fuzzy_hashes: "[]" sender: bounces@send.example.com rcpt: john.doe@example.org msg: "Return-Path: \r\nFrom: Prize \r\nTo: john.doe@example.org\r\nSubject: You have won\r\n\r\nClick here\r\n" domain: null notified: 1 created: "2026-11-10 09:47:14" user: unknown qhash: 3f9d8c0b2a4e6f1d7c5b9a8e0f2d4c6b8a1e3f5d7c9b0a2e4f6d8c1b3a5e7f9d "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/quarantine: post: summary: Edit quarantine settings description: >- Saves the global quarantine settings. Fields not sent are reset; a missing `retention_size` or `max_size` turns the quarantine off. The current values cannot be read through the API. Messages: `saved_settings`; errors `redis_error`. operationId: editQuarantineSettings tags: - Quarantine requestBody: content: application/json: schema: type: object properties: items: description: Ignored attr: type: object properties: action: type: string const: settings retention_size: type: [integer, string] description: Items kept per mailbox; 0 disables the quarantine max_size: type: [integer, string] description: Maximum size in MiB of a quarantined message; 0 disables the quarantine max_score: type: [number, string] description: No notification for messages with a higher spam score; empty = no limit max_age: type: [integer, string] description: Days an item is kept; 0 or less becomes 365 release_format: type: string enum: - raw - attachment default: raw description: Deliver released messages as they are or as an attachment of a new message exclude_domains: type: array items: type: string description: Domains and alias domains whose mail is not quarantined sender: type: string description: Sender of the notifications (invalid address = empty) subject: type: string description: Subject of the notifications bcc: type: string description: Address that gets a copy of every notification (invalid address = empty) redirect: type: string description: Address that gets all notifications instead of the mailboxes (invalid address = empty) html_tmpl: type: string description: HTML template of the notifications (empty = the default template) required: - action required: - attr example: items: - self attr: action: settings retention_size: "20" max_size: "15" max_score: "" max_age: "365" release_format: raw exclude_domains: - example.com sender: quarantine@example.org subject: Spam Quarantine Notification bcc: "" redirect: "" html_tmpl: "" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/recipient_map/{id}: get: tags: - Address Rewriting summary: Get recipient maps operationId: getRecipientMaps description: >- `all` lists the recipient maps, an ID returns one map with an extra member `"0": null`. `{}` if there is none or the caller is no administrator. parameters: - name: id in: path required: true description: "`all` or the ID of a recipient map" schema: type: string example: all responses: "200": description: The list of recipient maps (`all`) or one recipient map content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/RecipientMap" - $ref: "#/components/schemas/RecipientMap" examples: all: summary: get/recipient_map/all value: - id: 1 recipient_map_old: jane.doe@example.org recipient_map_new: jane.smith@example.org active: 1 created: "2026-11-04 08:30:00" modified: null - id: 2 recipient_map_old: "@example.net" recipient_map_new: "@example.org" active: 0 created: "2026-11-04 08:31:12" modified: "2026-11-05 17:02:45" one: summary: get/recipient_map/1 value: id: 1 recipient_map_old: jane.doe@example.org recipient_map_new: jane.smith@example.org active: 1 created: "2026-11-04 08:30:00" modified: null "0": null "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/bcc: post: tags: - Address Rewriting summary: Update BCC maps operationId: editBccMap description: >- Changes the BCC maps in `items`; fields not sent keep their value, `local_dest` cannot be changed. Same callers as add/bcc. `type` is not validated: send only `sender` or `rcpt`. Messages: `bcc_edited`; errors `bcc_must_be_email`, `bcc_exists`. requestBody: content: application/json: schema: type: object properties: items: description: IDs of the BCC maps, a single value or a list oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: bcc_dest: type: string description: E-mail address that gets the copies type: type: string enum: - sender - rcpt active: type: [boolean, integer, string] description: 1 = active, 0 = inactive required: - items - attr example: items: - 3 attr: bcc_dest: journal@example.com active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/recipient_map: post: tags: - Address Rewriting summary: Update recipient maps operationId: editRecipientMap description: >- Changes the recipient maps in `items`; fields not sent keep their value. `recipient_map_entry_exists` stops the call. Messages: `recipient_map_entry_saved`; errors `invalid_recipient_map_old`, `invalid_recipient_map_new`. requestBody: content: application/json: schema: type: object properties: items: description: IDs of the recipient maps, a single value or a list oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: recipient_map_old: type: string description: Original recipient, an e-mail address or a domain recipient_map_new: type: string description: New recipient, an e-mail address or a domain active: type: [boolean, integer, string] description: 1 = active, 0 = inactive required: - items - attr example: items: - 1 attr: recipient_map_new: jane.smith@example.org active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/relayhost/{id}: get: tags: - Routing summary: Get sender-dependent transports operationId: getRelayhosts description: >- `all` lists the sender-dependent transports, an ID returns one; the password is in clear text. `{}` if there is none or the caller is no administrator. parameters: - name: id in: path required: true description: "`all` or the ID of a sender-dependent transport" schema: type: string example: all responses: "200": description: The list of sender-dependent transports (`all`) or one entry content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/Relayhost" - $ref: "#/components/schemas/Relayhost" examples: all: summary: get/relayhost/all value: - id: 1 hostname: "[smtp.example.com]:587" username: relay-user@example.com password: Secret-Passphrase-42 active: 1 password_short: Sec... used_by_domains: example.org, example.net used_by_mailboxes: anna@example.com one: summary: get/relayhost/1 value: id: 1 hostname: "[smtp.example.com]:587" username: relay-user@example.com password: Secret-Passphrase-42 active: 1 password_short: Sec... used_by_domains: example.org, example.net used_by_mailboxes: anna@example.com "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/resource/all: get: tags: - Resources summary: Get all resources operationId: getResources description: >- All resources of the domains the caller manages, `{}` if none. responses: "200": description: List of resources content: application/json: schema: type: array items: $ref: "#/components/schemas/Resource" example: - name: MeetingRoom1@example.org kind: location multiple_bookings: 0 description: Meeting Room 1 active: 1 active_int: 1 domain: example.org local_part: MeetingRoom1 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/resource/{id}: get: tags: - Resources summary: Get a resource operationId: getResource description: >- One resource by address, `{}` if not found or no access. parameters: - name: id in: path required: true description: Address of the resource schema: type: string example: MeetingRoom1@example.org responses: "200": description: The resource content: application/json: schema: $ref: "#/components/schemas/Resource" "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/resource: post: tags: - Resources summary: Update resources operationId: editResource description: >- Changes resources, also for domain admins; fields not sent keep their value. The address does not change with the description. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Resource address or list of addresses oneOf: - type: string - type: array items: type: string attr: type: object properties: description: type: string description: Name shown in SOGo kind: type: string enum: - location - group - thing multiple_bookings: type: [integer, string] description: 0 always free, -1 unlimited but busy when booked, n ≥ 1 at most n overlapping bookings active: type: [integer, string] enum: [0, 1, "0", "1"] example: items: - MeetingRoom1@example.org attr: description: Meeting Room 1 (2nd floor) multiple_bookings: -1 active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/rl-mbox/{mailbox}: get: tags: - Ratelimits summary: Get the rate limit of a mailbox operationId: getMailboxRatelimit description: >- The rate limit set on the mailbox; `{}` if it has none (the domain limit applies) or no access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: The rate limit content: application/json: schema: $ref: "#/components/schemas/MailboxRatelimit" example: value: "100" frame: h "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/rl-domain/{domain}: get: summary: Get rate limits of domains description: >- Rate limit (outgoing messages per time frame) of a domain or alias domain; `all` lists all that have one. operationId: getDomainRatelimits tags: - Ratelimits parameters: - name: domain in: path required: true description: "`all` or a domain or alias domain name" schema: type: string example: example.org responses: "200": description: The rate limit, or the list of rate limits (`all`) content: application/json: schema: oneOf: - $ref: "#/components/schemas/DomainRatelimit" - type: array items: allOf: - $ref: "#/components/schemas/DomainRatelimit" - type: object properties: domain: type: string description: Domain or alias domain example: value: "100" frame: h "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/rl-domain: post: summary: Set rate limits of domains description: >- Sets the rate limit of domains or alias domains. Needs the ACL `ratelimit`. `rl_frame` is required also when removing the limit. Messages: `rl_saved`; error `rl_timeframe`. operationId: editDomainRatelimits tags: - Ratelimits requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Domain or alias domain name, or a list of them oneOf: - type: string - type: array items: type: string attr: type: object required: - rl_frame properties: rl_value: type: [integer, string] description: Messages per `rl_frame`; empty or 0 removes the limit rl_frame: type: string enum: [s, m, h, d] description: Time frame (second, minute, hour, day) example: items: - example.org attr: rl_value: 100 rl_frame: h responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/rl-mbox/all: get: tags: - Ratelimits summary: Get the rate limits of all mailboxes operationId: getMailboxRatelimits description: >- The rate limits set on single mailboxes the caller manages (no domain limits). `{}` if none. responses: "200": description: List of rate limits content: application/json: schema: type: array items: allOf: - $ref: "#/components/schemas/MailboxRatelimit" - type: object properties: mailbox: type: string example: - value: "100" frame: h mailbox: john.doe@example.org "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/rl-mbox: post: tags: - Ratelimits summary: Set the rate limit of mailboxes operationId: editMailboxRatelimit description: >- Sets the rate limit of mailboxes: `rl_value` messages per `rl_frame`. 0 or empty removes it, but `rl_frame` must still be valid. Domain admins need the ACL `ratelimit`. Answers `rl_saved` or `rl_timeframe`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object required: - rl_frame properties: rl_value: type: [integer, string] description: Number of messages, 0 or empty removes the limit rl_frame: type: string enum: - s - m - h - d description: Per second, minute, hour or day example: items: - john.doe@example.org attr: rl_value: 100 rl_frame: h responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/rlhash: post: tags: - Ratelimits summary: Reset a rate limit counter operationId: deleteRatelimitHash description: >- Resets the counter of a rate-limited sender (`rl_hash` from `get/logs/ratelimited`) so it can send again. Send one hash. Answers `1` (not JSON) when deleted, else an empty body. requestBody: required: true content: application/json: schema: type: array description: The hash items: type: string pattern: "^RL[0-9A-Za-z=]+$" example: - RLkfx5cv4sq1i3ehpkz5bgdhcq9u9gkzj responses: "200": description: "`1` if deleted, else an empty body" content: application/json: schema: type: integer const: 1 example: 1 "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/status/containers: get: summary: Get container status description: State, start time and image of all mailcow containers (also stopped ones). operationId: getContainerStatus tags: - Status responses: "200": description: The containers, `null` if dockerapi cannot be reached content: application/json: schema: type: object additionalProperties: $ref: "#/components/schemas/ContainerStatus" example: dovecot-mailcow: type: info container: dovecot-mailcow state: running started_at: "2026-11-10T11:00:51.541059812Z" image: ghcr.io/mailcow/dovecot:2.3.21.1-4 postfix-mailcow: type: info container: postfix-mailcow state: running started_at: "2026-11-10T11:00:51.292779901Z" image: ghcr.io/mailcow/postfix:1.80 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/status/vmail: get: summary: Get mail storage status description: Disk usage of the file system that holds the mail storage. operationId: getVmailStatus tags: - Status responses: "200": description: The disk usage (`df -H` values) content: application/json: schema: type: object properties: type: type: string const: info disk: type: string description: Device used: type: string description: Used space total: type: string description: Size of the file system used_percent: type: string description: Used space in percent example: type: info disk: /dev/sda1 used: 65G total: 105G used_percent: 66% "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/status/version: get: summary: Get mailcow version description: The installed mailcow version, the release tag on master, else the short commit ID. operationId: getVersion tags: - Status responses: "200": description: The version content: application/json: schema: type: object properties: version: type: [string, "null"] description: Release tag or commit ID example: version: "2026-11" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/status/container/{id}: get: summary: Get container statistics description: >- Up to three Docker stats snapshots of one container, about five seconds apart. Needs the full container ID, which the API does not list; an unknown ID answers after 60 seconds with an error string. operationId: getContainerStats tags: - Status parameters: - name: id in: path required: true description: Full Docker container ID schema: type: string example: 5d0f3cbb2a6e4f6c8e0e1c3b9a7d2f41b6c5e8a9d0f1e2c3b4a5968778695a4b responses: "200": description: >- Docker stats objects (see the Docker Engine API, `ContainerStats`), oldest first; `false` without ID content: application/json: schema: type: array items: type: object description: One Docker stats snapshot properties: read: type: string description: Time of the snapshot name: type: string id: type: string cpu_stats: type: object precpu_stats: type: object memory_stats: type: object blkio_stats: type: object networks: type: object pids_stats: type: object additionalProperties: true example: - read: "2026-11-10T19:20:01.123456789Z" name: /mailcowdockerized-dovecot-mailcow-1 id: 5d0f3cbb2a6e4f6c8e0e1c3b9a7d2f41b6c5e8a9d0f1e2c3b4a5968778695a4b pids_stats: current: 38 memory_stats: usage: 104857600 limit: 12541669376 blkio_stats: io_service_bytes_recursive: - major: 8 minor: 0 op: read value: 1052672 - major: 8 minor: 0 op: write value: 40960 networks: eth0: rx_bytes: 2621440 tx_bytes: 1048576 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/status/host: get: summary: Get host statistics description: CPU, memory, uptime and architecture of the Docker host. operationId: getHostStatus tags: - Status responses: "200": description: The host statistics content: application/json: schema: $ref: "#/components/schemas/HostStats" example: cpu: cores: 4 usage: 6 memory: total: 12541669376 usage: 62.5 swap: - 1022357504 - 512716800 - 509640704 - 50.2 - 1392812032 - 3864260608 uptime: 703800.5492310524 system_time: "10.11.2026 19:13:07" architecture: x86_64 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/status/host/ip: get: summary: Get public IP addresses description: >- The public IPv4 and IPv6 address of the server. Asks ipv4.mailcow.email and ipv6.mailcow.email on every call, even with the IP check off. operationId: getHostIps tags: - Status responses: "200": description: The addresses, `false` for an address that could not be determined content: application/json: schema: type: object properties: ipv4: type: [string, boolean] description: Public IPv4 address ipv6: type: [string, boolean] description: Public IPv6 address example: ipv4: 198.51.100.25 ipv6: 2001:db8::25 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjobs/all/no_log: get: summary: Get all sync jobs without logs description: >- Like `GET /api/v1/get/syncjobs/all`, with an empty `log`. operationId: getSyncJobsWithoutLog tags: - Sync jobs responses: "200": description: The sync jobs content: application/json: schema: type: array items: $ref: "#/components/schemas/SyncJob" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjob_source/{id}: get: summary: Get sync source description: >- One sync source by id, visible as in `GET /api/v1/get/syncjob_source/all`. operationId: getSyncJobSource tags: - Sync jobs parameters: - name: id in: path required: true description: Source id schema: type: integer example: 4 responses: "200": description: The sync source content: application/json: schema: $ref: "#/components/schemas/SyncJobSource" example: id: 4 name: Google Workspace description: "" created_by: admin scope: all host1: imap.gmail.com port1: 993 enc1: SSL verify_cert: 1 auth_type: XOAUTH2 oauth_flow: authorization_code oauth_token_endpoint: https://oauth2.googleapis.com/token oauth_authorize_endpoint: https://accounts.google.com/o/oauth2/v2/auth oauth_userinfo_endpoint: null oauth_client_id: 1234567890-example.apps.googleusercontent.com oauth_scope: https://mail.google.com/ openid email oauth_extra_params: '{"access_type":"offline","prompt":"consent"}' oauth_token_expires: null oauth_last_refresh_error: null oauth_last_refresh_attempt: null created: "2026-11-01 10:00:00" modified: null active: 1 domains: [] users: [] can_edit: true host: imap.gmail.com port: 993 enc: SSL has_client_secret: true has_access_token: false oauth_redirect_uri: https://mail.example.org/syncjob-oauth "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjob_options: get: summary: Get allowed custom imapsync options description: >- The imapsync options allowed in `custom_params`, with their rule: `true` needs a value, `false` takes none, a string is a regular expression the whole value must match. Options that run code, use local files or print secrets are never allowed. Every logged-in user may read it. operationId: getSyncJobOptions tags: - Sync jobs responses: "200": description: Option name => rule content: application/json: schema: type: object additionalProperties: type: - boolean - string example: authmd51: false debugssl: true folder: true maxsize: true syncinternaldates: false sslargs1: "^SSL_verify_mode=[01]$" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/imapsync_settings: get: summary: Get global sync job settings description: >- Settings of the sync job runner. operationId: getSyncJobSettings tags: - Sync jobs responses: "200": description: The settings content: application/json: schema: $ref: "#/components/schemas/SyncJobSettings" example: max_parallel: 3 max_bytes_per_second: 2048000 max_kb_per_second: 2000 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjobs/all: get: summary: Get all sync jobs description: >- All sync jobs with their logs, in queue order. Admins also get jobs of deleted mailboxes, domain admins the jobs of their mailboxes; users get none, see `GET /api/v1/get/syncjobs/{mailbox}`. operationId: getSyncJobs tags: - Sync jobs responses: "200": description: The sync jobs content: application/json: schema: type: array items: $ref: "#/components/schemas/SyncJob" example: - id: 12 user2: alice@example.org regextrans2: "" authmd51: 0 domain2: "" subfolder2: Imported user1: alice@old-provider.example.com exclude: "(?i)spam|(?i)junk" maxage: 0 mins_interval: 20 maxbytespersecond: "0" delete2duplicates: 1 delete1: 0 delete2: 0 automap: 1 skipcrossduplicates: 0 custom_params: '[{"o":"folder","v":"INBOX"}]' timeout1: 600 timeout2: 600 subscribeall: 1 dry: 0 is_running: 0 last_run: "2026-11-09 08:20:01" success: 1 exit_status: EX_OK created: "2026-11-03 09:40:09" modified: "2026-11-03 09:42:21" active: 1 source_id: 3 custom_params_legacy: null prio: 0 source_name: Old provider source_description: Migration from the old provider source_host: imap.example.com source_port: 993 source_enc: SSL source_auth_type: PLAIN source_created_by: API source_scope: domain source_oauth_flow: client_credentials source_active: 1 source_oauth_token_expires: null source_oauth_last_refresh_error: null user_token_expires: null user_token_error: null user_token_exists: 0 log: "Transfer started at Mon Nov 9 08:20:02 2026\n..." "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjobs/{mailbox}: get: summary: Get sync jobs of a mailbox description: >- The sync jobs of a local mailbox with their logs, in queue order. Domain admins may read their mailboxes, users their own. A value that is no email address returns the caller's own jobs. operationId: getMailboxSyncJobs tags: - Sync jobs parameters: - name: mailbox in: path required: true description: Local mailbox (`user2` of the jobs) schema: type: string example: alice@example.org responses: "200": description: The sync jobs of the mailbox content: application/json: schema: type: array items: $ref: "#/components/schemas/SyncJob" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjobs/{mailbox}/no_log: get: summary: Get sync jobs of a mailbox without logs description: >- Like `GET /api/v1/get/syncjobs/{mailbox}`, with an empty `log`. operationId: getMailboxSyncJobsWithoutLog tags: - Sync jobs parameters: - name: mailbox in: path required: true description: Local mailbox (`user2` of the jobs) schema: type: string example: alice@example.org responses: "200": description: The sync jobs of the mailbox content: application/json: schema: type: array items: $ref: "#/components/schemas/SyncJob" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/syncjob_source/all: get: summary: Get sync sources description: >- The sync sources the caller may see, ordered by name. Domain admins see their own, `all` sources and those for their domains or mailboxes or created by their mailboxes; users their own, `all` sources and those for them or their domain. operationId: getSyncJobSources tags: - Sync jobs responses: "200": description: The sync sources content: application/json: schema: type: array items: $ref: "#/components/schemas/SyncJobSource" example: - id: 3 name: Old provider description: Migration from the old provider created_by: API scope: domain host1: imap.example.com port1: 993 enc1: SSL verify_cert: 1 auth_type: PLAIN oauth_flow: client_credentials oauth_token_endpoint: null oauth_authorize_endpoint: null oauth_userinfo_endpoint: null oauth_client_id: null oauth_scope: null oauth_extra_params: null oauth_token_expires: null oauth_last_refresh_error: null oauth_last_refresh_attempt: null created: "2026-11-03 09:42:21" modified: null active: 1 domains: - example.org users: [] can_edit: true host: imap.example.com port: 993 enc: SSL has_client_secret: false has_access_token: false "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/tls-policy-map/{id}: get: tags: - Outgoing TLS Policy Map Overrides summary: Get TLS policy maps operationId: getTlsPolicyMaps description: >- `all` lists the TLS policy maps, an ID returns one map with an extra member `"0": null`. `{}` if there is none or the caller is no administrator. parameters: - name: id in: path required: true description: "`all` or the ID of a TLS policy map" schema: type: string example: all responses: "200": description: The list of TLS policy maps (`all`) or one TLS policy map content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/TlsPolicyMap" - $ref: "#/components/schemas/TlsPolicyMap" examples: all: summary: get/tls-policy-map/all value: - id: 2 dest: example.com policy: encrypt parameters: protocols=>=TLSv1.2 active: 1 created: "2026-11-06 12:00:31" modified: null one: summary: get/tls-policy-map/2 value: id: 2 dest: example.com policy: encrypt parameters: protocols=>=TLSv1.2 active: 1 created: "2026-11-06 12:00:31" modified: null "0": null "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/tls-policy-map: post: tags: - Outgoing TLS Policy Map Overrides summary: Update TLS policy maps operationId: editTlsPolicyMap description: >- Changes the TLS policy maps in `items`; fields not sent keep their value. An error stops the call; an existing destination answers `recipient_map_entry_exists`. Messages: `tls_policy_map_entry_saved`; errors `tls_policy_map_dest_invalid`, `tls_policy_map_parameter_invalid`. requestBody: content: application/json: schema: type: object properties: items: description: IDs of the TLS policy maps, a single value or a list oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: dest: type: string description: Destination, e.g. `example.org` or `[mail.example.org]:25` policy: type: string enum: - none - may - encrypt - dane - dane-only - fingerprint - verify - secure parameters: type: string description: Empty or space-separated `name=value` attributes active: type: [boolean, integer, string] description: 1 = active, 0 = inactive required: - items - attr example: items: - 2 attr: policy: dane parameters: "" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/transport/{id}: get: tags: - Routing summary: Get transport maps operationId: getTransports description: >- `all` lists the transport maps, an ID returns one; the password is in clear text. `{}` if there is none or the caller is no administrator. parameters: - name: id in: path required: true description: "`all` or the ID of a transport map" schema: type: string example: all responses: "200": description: The list of transport maps (`all`) or one entry content: application/json: schema: anyOf: - type: array items: $ref: "#/components/schemas/Transport" - $ref: "#/components/schemas/Transport" examples: all: summary: get/transport/all value: - id: 4 is_mx_based: 0 destination: example.com nexthop: "[mx.example.com]:25" username: "" password: "" active: 1 password_short: "..." - id: 5 is_mx_based: 1 destination: .*\.google\.com nexthop: "[smtp.example.net]:587" username: relay-user@example.net password: Secret-Passphrase-42 active: 1 password_short: Sec... one: summary: get/transport/4 value: id: 4 is_mx_based: 0 destination: example.com nexthop: "[mx.example.com]:25" username: "" password: "" active: 1 password_short: "..." "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/relayhost: post: tags: - Routing summary: Update sender-dependent transports operationId: editRelayhost description: >- Changes the sender-dependent transports in `items`; fields not sent and an empty `hostname` keep their value. Messages: `object_modified`; errors `relayhost_invalid`. requestBody: content: application/json: schema: type: object properties: items: description: IDs of the sender-dependent transports, a single value or a list oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: hostname: type: string description: Next hop, e.g. `[smtp.example.com]:587` username: type: string description: SMTP user name, empty for no authentication password: type: string description: SMTP password active: type: [boolean, integer, string] description: 1 = active, 0 = inactive required: - items - attr example: items: - 1 attr: password: New-Secret-Passphrase-43 active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/transport: post: tags: - Routing summary: Update transport maps operationId: editTransport description: >- Changes the transport maps in `items`; fields not sent keep their value. An empty `username` also clears the password; credentials apply to all entries of the next hop. Destination and next-hop errors stop the call. Messages: `object_modified`; errors `relayhost_invalid`, `transport_dest_exists`, `invalid_destination`, `next_hop_interferes`. requestBody: content: application/json: schema: type: object properties: items: description: IDs of the transport maps, a single value or a list oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: destination: type: string description: One destination (see add/transport) nexthop: type: string description: Next hop, e.g. `[mx.example.com]:25` username: type: string description: SMTP user name; empty removes the credentials password: type: string description: SMTP password is_mx_based: type: [boolean, integer, string] description: 1 = `destination` is a regular expression for MX names active: type: [boolean, integer, string] description: 1 = active, 0 = inactive required: - items - attr example: items: - 4 attr: nexthop: "[mx2.example.com]:25" active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/cors: post: summary: Edit CORS settings description: >- Sets the origins and methods allowed to call the API from a browser. A missing value is reset to its default. Messages: `cors_headers_edited`; errors `cors_invalid_origin`, `cors_invalid_method`. operationId: editCors tags: - Cross-Origin Resource Sharing (CORS) requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: allowed_origins: description: >- `scheme://host[:port]` (http/https, no path) or `*`; a list or one origin per line. Default: the mailcow URL. oneOf: - type: array items: type: string - type: string allowed_methods: description: >- Uppercase; a list or a string with single separators (`GET,POST`, not `GET, POST`). Default: all four. oneOf: - type: array items: type: string enum: - GET - POST - PUT - DELETE - type: string required: - attr example: attr: allowed_origins: - https://app.example.org - https://admin.example.com:8443 allowed_methods: - GET - POST responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/spam-score/{mailbox}: get: tags: - Mailbox user settings summary: Get the spam score of a mailbox operationId: getSpamScore description: >- The spam thresholds of the mailbox, its own or the server default. `{}` without access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: Thresholds content: application/json: schema: $ref: "#/components/schemas/SpamScore" example: score: "6,12" "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/spam-score: post: tags: - Mailbox user settings summary: Set the spam score of mailboxes operationId: editSpamScore description: >- Sets the spam thresholds of the mailboxes: from the first value mail goes to junk, from the second it is rejected. `default` removes the own values. Needs the user ACL `spam_score`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: $ref: "#/components/schemas/MailboxItems" attr: type: object required: - spam_score properties: spam_score: type: string description: '"low,high" (numbers) or "default"' examples: - "6,12" - default example: items: - john.doe@example.org attr: spam_score: "6,12" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/mailbox/template: post: tags: - Mailboxes summary: Create a mailbox template operationId: addMailboxTemplate description: >- Saves a named set of mailbox settings that `add/mailbox` uses as defaults. Without `acl` it grants no user ACL. Messages: `template_added`; errors `template_exists`, `quarantine_category_invalid`. requestBody: required: true content: application/json: schema: allOf: - type: object required: - template properties: template: type: string description: Name of the template - $ref: "#/components/schemas/MailboxTemplateInput" example: template: Sales quota: 2048 tags: - sales quarantine_notification: daily quarantine_category: reject rl_value: 100 rl_frame: h active: 1 protocol_access: - imap - smtp - sieve acl: - spam_alias - spam_score - app_passwds responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/mailbox/all: get: tags: - Mailboxes summary: Get all mailboxes operationId: getMailboxes description: >- All mailboxes of the domains the caller manages, without resources. `{}` if none. parameters: - $ref: "#/components/parameters/MailboxTagsQuery" responses: "200": description: List of mailboxes content: application/json: schema: type: array items: $ref: "#/components/schemas/Mailbox" examples: mailboxes: $ref: "#/components/examples/MailboxList" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox/all/{domains}: get: tags: - Mailboxes summary: Get the mailboxes of domains operationId: getMailboxesOfDomains description: >- Like `get/mailbox/all` for the given domains. Caution: an unknown or foreign domain adds all mailboxes the caller manages. parameters: - name: domains in: path required: true description: Domain name or comma-separated list of domain names schema: type: string example: example.org - $ref: "#/components/parameters/MailboxTagsQuery" responses: "200": description: List of mailboxes content: application/json: schema: type: array items: $ref: "#/components/schemas/Mailbox" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox/reduced: get: tags: - Mailboxes summary: Get all mailboxes (reduced details) operationId: getMailboxesReduced description: >- Like `get/mailbox/all` without the costly fields named in `Mailbox`; faster on large installations. parameters: - $ref: "#/components/parameters/MailboxTagsQuery" responses: "200": description: List of mailboxes content: application/json: schema: type: array items: $ref: "#/components/schemas/Mailbox" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox/reduced/{domains}: get: tags: - Mailboxes summary: Get the mailboxes of domains (reduced details) operationId: getMailboxesReducedOfDomains description: >- Like `get/mailbox/reduced` for the given domains; an unknown domain adds all mailboxes the caller manages. parameters: - name: domains in: path required: true description: Domain name or comma-separated list of domain names schema: type: string example: example.org,example.com - $ref: "#/components/parameters/MailboxTagsQuery" responses: "200": description: List of mailboxes content: application/json: schema: type: array items: $ref: "#/components/schemas/Mailbox" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox/template/all: get: tags: - Mailboxes summary: Get all mailbox templates operationId: getMailboxTemplates description: >- All mailbox templates, also for domain admins. `{}` if none. responses: "200": description: List of templates content: application/json: schema: type: array items: $ref: "#/components/schemas/MailboxTemplate" example: - id: 2 template: Default type: mailbox attributes: tags: [] quota: 0 quarantine_notification: hourly quarantine_category: reject rl_frame: s rl_value: "" force_pw_update: 0 force_tfa: 0 sogo_access: 1 active: 1 tls_enforce_in: 0 tls_enforce_out: 0 imap_access: 1 pop3_access: 1 smtp_access: 1 sieve_access: 1 eas_access: 1 dav_access: 1 acl_spam_alias: 1 acl_tls_policy: 1 acl_spam_score: 1 acl_spam_policy: 1 acl_delimiter_action: 1 acl_syncjobs: 0 acl_eas_reset: 1 acl_sogo_profile_reset: 0 acl_pushover: 1 acl_quarantine: 1 acl_quarantine_attachments: 1 acl_quarantine_notification: 1 acl_quarantine_category: 1 acl_app_passwds: 1 created: "2026-09-21 10:23:08" modified: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/mailbox/template/{id}: get: tags: - Mailboxes summary: Get a mailbox template operationId: getMailboxTemplate description: >- One mailbox template by ID, also for domain admins. `{}` if not found. parameters: - name: id in: path required: true description: Template ID schema: type: integer example: 2 responses: "200": description: The template content: application/json: schema: $ref: "#/components/schemas/MailboxTemplate" "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/mailbox/template: post: tags: - Mailboxes summary: Update mailbox templates operationId: editMailboxTemplate description: >- Changes mailbox templates and passes the change on to mailboxes that use them as group template. `Default` keeps its name. Send the complete template: fields not sent are reset (`quota` to 0, protocol and ACL settings lost), and `quarantine_category` is required. Messages: `template_modified`; errors `template_id_invalid`, `quarantine_category_invalid`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Template ID or list of template IDs oneOf: - type: integer - type: array items: type: integer attr: allOf: - type: object properties: template: type: string description: New name of the template (not for "Default") - $ref: "#/components/schemas/MailboxTemplateInput" example: items: - 3 attr: template: Sales quota: 4096 tags: - sales tagged_mail_handler: subfolder quarantine_notification: daily quarantine_category: reject rl_value: 100 rl_frame: h force_pw_update: 0 force_tfa: 0 sogo_access: 1 active: 1 tls_enforce_in: 0 tls_enforce_out: 1 protocol_access: - imap - smtp - sieve - dav acl: - spam_alias - spam_score - delimiter_action - app_passwds responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/rename-mbox: post: tags: - Mailboxes summary: Rename a mailbox operationId: renameMailbox description: >- Renames `old_local_part@domain` to `new_local_part@domain`, including maildir, aliases and SOGo account. The mailbox is named in `attr`, not `items`, and must be active (1 or 2). Also for domain admins. Answers `mailbox_renamed`. requestBody: required: true content: application/json: schema: type: object required: - attr properties: items: description: Not used attr: type: object required: - domain - old_local_part - new_local_part properties: domain: type: string description: Domain of the mailbox old_local_part: type: string description: Current local part new_local_part: type: string description: New local part create_alias: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 description: 1 creates an alias from the old to the new address example: items: [] attr: domain: example.org old_local_part: john.doe new_local_part: john create_alias: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/mailbox/template: post: tags: - Mailboxes summary: Delete mailbox templates operationId: deleteMailboxTemplate description: >- Deletes mailbox templates by ID; `Default` is kept silently. Answers `template_removed`. requestBody: required: true content: application/json: schema: type: array description: Template IDs items: type: integer example: - 3 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/last-login/{mailbox}: get: tags: - Mailboxes summary: Get the last logins of a mailbox operationId: getLastLogin description: >- Logins of the mailbox in the last 7 days (`sasl`, the latest per address, service and app password) and its previous UI login (`ui`, only for admins and the mailbox user itself). parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: Logins content: application/json: schema: $ref: "#/components/schemas/LastLogin" example: ui: remote: 198.51.100.23 time: 1793011200 sasl: - real_rip: 198.51.100.23 datetime: "2026-11-09 08:12:44" service: imap app_password: 23 app_password_name: Thunderbird location: DE - real_rip: Web/EAS/Internal (172.22.1.248) datetime: "2026-11-08 17:03:10" service: SOGO app_password: 0 app_password_name: null "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/last-login/{mailbox}/{days}: get: tags: - Mailboxes summary: Get the last logins of a mailbox for a period operationId: getLastLoginDays description: >- Like `get/last-login/{mailbox}` for the last `{days}` days; values below 1 mean 7. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org - name: days in: path required: true description: Number of days schema: type: integer minimum: 1 example: 30 responses: "200": description: Logins content: application/json: schema: $ref: "#/components/schemas/LastLogin" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/reset-last-login/{mailbox}: get: tags: - Mailboxes summary: Clear the login history of a mailbox operationId: resetLastLogin description: >- Deletes the login history of the mailbox. A `get` route that changes data: read-only API keys can call it. Always answers `true`. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: Done content: application/json: schema: type: boolean example: true "401": $ref: "#/components/responses/Unauthorized" /api/v1/delete/eas_cache: post: tags: - Mailboxes summary: Reset the ActiveSync devices of mailboxes operationId: deleteEasCache description: >- Deletes the ActiveSync device cache of the mailboxes, so devices sync from scratch. Needs the user ACL `eas_reset`; a mailbox user may reset only its own. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MailboxItems" example: - john.doe@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/sogo_profile: post: tags: - Mailboxes summary: Reset the SOGo profile of mailboxes operationId: deleteSogoProfile description: >- Deletes the SOGo data of the mailboxes: profile, settings, calendars and address books. Needs the user ACL `sogo_profile_reset`; a mailbox user may reset only its own. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MailboxItems" example: - john.doe@example.org responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/bcc-destination-options: get: tags: - Mailboxes summary: Get the possible BCC map destinations operationId: getBccDestinationOptions description: >- What a BCC map can be bound to: the caller's domains, their mailboxes with their aliases, and alias domains. Empty keys are left out. responses: "200": description: Domains, mailboxes with their addresses, alias domains content: application/json: schema: type: object properties: domains: type: array items: type: string mailboxes: type: object description: Mailbox address → the mailbox and its aliases additionalProperties: type: array items: type: string alias_domains: type: array items: type: string example: domains: - example.org mailboxes: john.doe@example.org: - john.doe@example.org - sales@example.org jane.roe@example.org: - jane.roe@example.org alias_domains: - example.net "401": $ref: "#/components/responses/Unauthorized" /api/v1/search/mailbox: post: tags: - Mailboxes summary: Search mailboxes page by page operationId: searchMailboxes description: >- Server-side search behind the UI mailbox table (DataTables format) over the mailboxes the caller manages. Read-only API keys may use it; mailbox users get `403`. Columns: 2 address, 3 quota, 4 last mail login, 5 last password change, 6 quota in use, 7 name, 20 messages, 23 tags, 24 active. Send 4, 5, 6 and 20 as not searchable and 23 as not orderable, else the query fails. `recordsTotal` equals `recordsFiltered`. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MailboxSearchRequest" example: draw: 1 start: 0 length: 25 search: value: john order: - column: 2 dir: asc columns: - searchable: false orderable: false - searchable: false orderable: false - data: username searchable: true orderable: true - searchable: false orderable: true - searchable: false orderable: true - searchable: false orderable: true - searchable: false orderable: true - data: name searchable: true orderable: true responses: "200": description: >- One page of mailboxes. A failing database query answers `{"error": "An SQL error occurred: ..."}` instead. content: application/json: schema: oneOf: - $ref: "#/components/schemas/MailboxSearchResult" - type: object properties: error: type: string examples: page: $ref: "#/components/examples/MailboxSearchPage" "401": $ref: "#/components/responses/Unauthorized" "403": description: The caller is a mailbox user or not logged in content: application/json: schema: $ref: "#/components/schemas/Error" example: type: error msg: Insufficient permissions /api/v1/edit/identity-provider: post: summary: Configure the Identity Provider description: >- Saves the Identity Provider configuration (Keycloak, generic OpenID Connect or LDAP). Send the complete configuration including the secrets: settings not sent are reset to their defaults. Changing the LDAP `id_attribute` drops the stored links; mailboxes are matched by email again. Messages: `object_modified`; errors `required_data_missing`, `invalid_authsource`, `authsource_in_use`. operationId: editIdentityProvider tags: - Identity Provider requestBody: content: application/json: schema: type: object required: - attr properties: items: description: Not used attr: $ref: "#/components/schemas/IdentityProviderAttributes" examples: keycloak: value: attr: authsource: keycloak server_url: https://auth.example.org realm: mailcow client_id: mailcow client_secret: client-secret-value redirect_url: https://mail.example.org redirect_url_extra: - https://webmail.example.org version: 26.1.3 login_provisioning: 1 mailpassword_flow: 0 periodic_sync: 1 import_users: 1 sync_interval: 15 offboarding: 1 offboarding_limit: 10 group_sync: 1 group_autocreate: 1 group_paths: /mailcow/* group_default_domain: example.org default_template: Default mappers: - staff templates: - Staff ldap: value: attr: authsource: ldap host: ldap1.example.org,ldap2.example.org port: 636 use_ssl: 1 use_tls: 0 ignore_ssl_error: 0 basedn: dc=example,dc=org binddn: cn=mailcow,ou=services,dc=example,dc=org bindpass: bind-password username_field: mail filter: (objectClass=inetOrgPerson) attribute_field: departmentNumber login_provisioning: 1 periodic_sync: 1 import_users: 1 sync_interval: 30 group_sync: 1 group_filter: (objectClass=groupOfNames) group_member_mode: member group_member_attribute: member default_template: Default generic-oidc: value: attr: authsource: generic-oidc authorize_url: https://sso.example.org/application/o/authorize/ token_url: https://sso.example.org/application/o/token/ userinfo_url: https://sso.example.org/application/o/userinfo/ client_id: mailcow client_secret: client-secret-value redirect_url: https://mail.example.org client_scopes: openid profile email mailcow_template login_provisioning: 1 default_template: Default responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/identity-provider: get: summary: Get Identity Provider settings description: >- The stored Identity Provider settings, also those of providers configured before. Read/write API keys get the secrets in plain text, read-only keys `*`. Without a configuration it answers `{"login_provisioning": 1}`. operationId: getIdentityProvider tags: - Identity Provider responses: "200": description: The settings content: application/json: schema: $ref: "#/components/schemas/IdentityProviderSettings" example: authsource: keycloak server_url: https://auth.example.org realm: mailcow client_id: mailcow client_secret: "*" redirect_url: https://mail.example.org redirect_url_extra: - https://webmail.example.org version: 26.1.3 mailpassword_flow: "0" periodic_sync: "1" import_users: "1" sync_interval: "15" ignore_ssl_error: false login_provisioning: true group_paths: /mailcow/* offboarding: "1" offboarding_limit: "10" group_sync: "1" group_autocreate: "1" group_default_domain: example.org default_template: Default mappers: - staff templates: - Staff access_token: "*" "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/identity-provider-test: post: summary: Test an Identity Provider connection description: >- Tests the connection data in `attr` without storing it; stored settings are not used, so send the secrets too. Keycloak must issue a client_credentials token and generic-oidc answer OPTIONS on `token_url` (HTTP 200 within 7 s); LDAP must bind. The answer has no details, and a missing or unknown `authsource` answers success without a test. operationId: testIdentityProvider tags: - Identity Provider requestBody: content: application/json: schema: type: object required: - attr properties: items: description: Not used attr: type: object required: - authsource properties: authsource: type: string enum: - keycloak - generic-oidc - ldap server_url: type: string description: Keycloak base URL realm: type: string description: Keycloak realm client_id: type: string description: Keycloak client id client_secret: type: string description: Keycloak client secret token_url: type: string description: generic-oidc token endpoint ignore_ssl_error: type: - boolean - integer - string description: Do not verify the TLS certificate host: type: string description: LDAP host, or several separated by commas port: type: - integer - string description: LDAP port basedn: type: string binddn: type: string bindpass: type: string use_ssl: type: - boolean - integer - string description: LDAPS use_tls: type: - boolean - integer - string description: StartTLS, ignored with `use_ssl` example: attr: authsource: keycloak server_url: https://auth.example.org realm: mailcow client_id: mailcow client_secret: client-secret-value ignore_ssl_error: 0 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/identity-provider: post: summary: Delete the Identity Provider configuration description: >- Deletes all Identity Provider settings, mailbox links and the sync history. Refused while any mailbox uses an external provider. The body must be valid JSON, e.g. `[]`. Messages: `item_deleted`; errors `authsource_in_use`. operationId: deleteIdentityProvider tags: - Identity Provider requestBody: content: application/json: schema: description: Not used, any JSON value example: [] responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/filter: post: tags: - Mailbox filters summary: Create a Sieve filter operationId: addFilter description: >- Adds a Sieve script to a mailbox. Needs the ACL `filters` (admins, domain admins). Activating a filter deactivates the other filters of the same type and mailbox. Messages: `mailbox_modified`; errors `sieve_error`, `no_user_defined`, `script_empty`. requestBody: required: true content: application/json: schema: type: object required: - username - script_data - script_desc - filter_type properties: username: type: string description: Mailbox of the filter script_desc: type: string description: Description script_data: type: string description: The Sieve script filter_type: type: string enum: - prefilter - postfilter description: Runs before (prefilter) or after (postfilter) the user's own filters active: type: [integer, string] enum: [0, 1, "0", "1"] default: 0 example: username: john.doe@example.org script_desc: Move newsletters script_data: |- require "fileinto"; if header :contains "List-Id" "newsletter" { fileinto "Newsletters"; } filter_type: prefilter active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/filters/all: get: tags: - Mailbox filters summary: Get all Sieve filters operationId: getFilters description: >- The Sieve filters of all mailboxes the caller manages, `{}` if none. responses: "200": description: List of filters content: application/json: schema: type: array items: $ref: "#/components/schemas/SieveFilter" example: - active: 1 id: 7 username: john.doe@example.org filter_type: prefilter script_data: |- require "fileinto"; if header :contains "List-Id" "newsletter" { fileinto "Newsletters"; } script_desc: Move newsletters "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/filters/{mailbox}: get: tags: - Mailbox filters summary: Get the Sieve filters of a mailbox operationId: getMailboxFilters description: >- The Sieve filters of the mailbox, `{}` if none or no access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: List of filters content: application/json: schema: type: array items: $ref: "#/components/schemas/SieveFilter" "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/filter: post: tags: - Mailbox filters summary: Update Sieve filters operationId: editFilter description: >- Changes filters by ID; fields not sent keep their value. Needs the ACL `filters` (admins, domain admins). Activating a filter deactivates the others of the same type and mailbox. An unknown ID answers `access_denied`. requestBody: required: true content: application/json: schema: type: object required: - items - attr properties: items: description: Filter ID or list of IDs oneOf: - type: integer - type: array items: type: integer attr: type: object properties: script_desc: type: string script_data: type: string filter_type: type: string enum: - prefilter - postfilter active: type: [integer, string] enum: [0, 1, "0", "1"] example: items: - 7 attr: active: 0 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/filter: post: tags: - Mailbox filters summary: Delete Sieve filters operationId: deleteFilter description: >- Deletes filters by ID; IDs that are not numeric are skipped. Needs the ACL `filters` (admins, domain admins). requestBody: required: true content: application/json: schema: type: array description: Filter IDs items: type: integer example: - 7 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/active-user-sieve/{mailbox}: get: tags: - Mailbox filters summary: Get the active Sieve script of a mailbox operationId: getActiveUserSieve description: >- The Sieve script the user activated in a mail client or SOGo, as a list with one string. `{}` if none or no access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: The script as the only element of a list content: application/json: schema: type: array maxItems: 1 items: type: string example: - |- require ["fileinto"]; if header :contains "subject" "invoice" { fileinto "Invoices"; } "401": $ref: "#/components/responses/Unauthorized" /api/v1/add/mailbox-policy: post: tags: - Mailbox antispam policies summary: Add a sender to the allow or deny list of a mailbox operationId: addMailboxPolicy description: >- Adds a sender to the allow list (`wl`, never spam) or deny list (`bl`, rejected) of a mailbox. Needs the user ACL `spam_policy`. Messages: `mailbox_modified`; errors `policy_list_from_invalid`, `policy_list_from_exists`. requestBody: required: true content: application/json: schema: type: object required: - username - object_list - object_from properties: username: type: string description: Mailbox object_list: type: string enum: - wl - bl description: wl = allow list, bl = deny list object_from: type: string description: "Sender address, domain or pattern; allowed: letters, digits, `@ _ . - *`" example: username: john.doe@example.org object_list: bl object_from: "*@spam.example.com" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/policy_wl_mailbox/{mailbox}: get: tags: - Mailbox antispam policies summary: Get the allow list of a mailbox operationId: getMailboxPolicyAllowList description: >- The allow list entries of the mailbox and of its domain (see `object`). `{}` if none or no access. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: List of entries content: application/json: schema: type: array items: $ref: "#/components/schemas/SpamPolicyEntry" example: - object: john.doe@example.org value: "*@partner.example.com" prefid: 12 - object: example.org value: newsletter@example.net prefid: 4 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/policy_bl_mailbox/{mailbox}: get: tags: - Mailbox antispam policies summary: Get the deny list of a mailbox operationId: getMailboxPolicyDenyList description: >- Like `get/policy_wl_mailbox/{mailbox}` for the deny list. parameters: - name: mailbox in: path required: true description: Mailbox address schema: type: string example: john.doe@example.org responses: "200": description: List of entries content: application/json: schema: type: array items: $ref: "#/components/schemas/SpamPolicyEntry" example: - object: john.doe@example.org value: "*@spam.example.com" prefid: 13 "401": $ref: "#/components/responses/Unauthorized" /api/v1/delete/mailbox-policy: post: tags: - Mailbox antispam policies summary: Delete allow or deny list entries of mailboxes operationId: deleteMailboxPolicy description: >- Deletes allow or deny list entries of mailboxes by `prefid`. Needs the user ACL `spam_policy`. Domain entries are refused; use `delete/domain-policy`. requestBody: required: true content: application/json: schema: type: array description: prefid values items: type: integer example: - 13 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/add/rsetting: post: summary: Add Rspamd settings rule description: >- Adds a rule to the Rspamd settings map. `content` is an Rspamd settings entry; `GET /api/v1/get/presets/rspamd` has examples. Without `desc` nothing is saved and the answer is empty. Messages: `settings_map_added`; errors `map_content_empty`. operationId: addRspamdSetting tags: - Rspamd requestBody: content: application/json: schema: $ref: "#/components/schemas/RspamdSettingAttributes" example: desc: Disable all but DKIM and rate limit for authenticated users content: |- priority = 10; authenticated = yes; apply "default" { symbols_enabled = ["DKIM_SIGNED", "RATELIMITED", "RATELIMIT_UPDATE", "RATELIMIT_CHECK"]; } active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/rsetting/{id}: get: summary: Get Rspamd settings rules description: >- Returns one rule of the Rspamd settings map, or a list of all rules with `all`. operationId: getRspamdSettings tags: - Rspamd parameters: - name: id in: path required: true description: "`all` or the ID of a rule" schema: type: string example: all responses: "200": description: The rule, or the list of rules for `all` content: application/json: schema: oneOf: - type: array items: $ref: "#/components/schemas/RspamdSetting" - $ref: "#/components/schemas/RspamdSetting" example: - id: 1 desc: Disable Rspamd for example.org content: |- priority = 10; rcpt = "/.*@example\.org$/"; from = "/.*/"; apply "default" { MAILCOW_WHITE = -9999.0; } symbols [ "MAILCOW_WHITE" ] active: 1 "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/rsetting: post: summary: Edit Rspamd settings rules description: >- Changes rules of the Rspamd settings map. Fields not sent, and an empty `desc` or `content`, keep the old value. Messages: `object_modified`; errors `settings_map_invalid`. operationId: editRspamdSetting tags: - Rspamd requestBody: content: application/json: schema: type: object properties: items: description: ID or list of IDs of the rules oneOf: - type: array items: type: [integer, string] - type: [integer, string] attr: type: object properties: desc: type: string description: Short description (empty = keep) content: type: string description: Rule content (empty = keep) active: type: [boolean, integer, string] description: 1 = the rule is handed to Rspamd, 0 = inactive (not sent = keep) required: - items - attr example: items: - 1 attr: desc: Disable Rspamd for example.org active: "0" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/rsetting: post: summary: Delete Rspamd settings rules description: >- Deletes rules of the Rspamd settings map. Answers `settings_map_removed` for every ID, even unknown ones. operationId: deleteRspamdSettings tags: - Rspamd requestBody: content: application/json: schema: description: IDs of the rules (a single ID works too) oneOf: - type: array items: type: [integer, string] - type: [integer, string] example: - 1 - 2 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/rspamd-map: post: summary: Edit Rspamd global regex maps description: >- Replaces the content of global Rspamd regex maps (Global filters in the UI). One regular expression per line, `#` starts a comment; unlike the UI, the API does not check the expressions. Each map takes about a second. Messages: `object_modified`; errors `global_map_invalid`, `global_map_write_error`. operationId: editRspamdMap tags: - Rspamd requestBody: content: application/json: schema: type: object properties: items: description: File name or list of file names of the maps; all of them get the same content oneOf: - type: array items: $ref: "#/components/schemas/RspamdRegexMap" - $ref: "#/components/schemas/RspamdRegexMap" attr: type: object properties: rspamd_map_data: type: string description: New content of the map (trimmed, replaces the whole file) required: - rspamd_map_data required: - items - attr example: items: - global_smtp_from_blacklist.map attr: rspamd_map_data: |- # Envelope senders to reject /^spammer@example\.com$/i /@spam\.example\.net$/i responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/rspamd/actions: get: summary: Get Rspamd action statistics description: >- Returns how many messages Rspamd handled with each action, as `[action, count]` pairs. Greylisted messages count as `soft reject`. `{}` when Rspamd does not answer. operationId: getRspamdActions tags: - Rspamd responses: "200": description: List of `[action, count]` pairs content: application/json: schema: type: array items: type: array prefixItems: - type: string description: Rspamd action - type: integer description: Number of messages minItems: 2 maxItems: 2 example: - - reject - 38 - - soft reject - 1 - - rewrite subject - 0 - - add header - 6 - - no action - 255 "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/presets/{kind}: get: summary: Get Rspamd or Sieve presets description: >- Returns the example presets of the UI: `rspamd` for Rspamd settings rules, `sieve` for Sieve filters. `headline` is in the session language. Admins and domain admins. operationId: getPresets tags: - Rspamd - Global filters parameters: - name: kind in: path required: true description: Kind of presets schema: type: string enum: - rspamd - sieve example: rspamd responses: "200": description: List of presets content: application/json: schema: type: array items: $ref: "#/components/schemas/Preset" example: - name: preset_1 headline: Disable all but DKIM and rate limit for authenticated users content: |- priority = 10; authenticated = yes; apply "default" { symbols_enabled = ["BCC", "DKIM_SIGNED", "RATELIMITED", "RATELIMIT_UPDATE", "RATELIMIT_CHECK", "DYN_RL_CHECK", "HISTORY_SAVE", "MILTER_HEADERS", "ARC_SIGNED"]; } - name: preset_4 headline: Disable Rspamd for a domain content: |- priority = 10; rcpt = "/.*@example.org$/"; from = "/.*/"; apply "default" { MAILCOW_WHITE = -9999.0; } symbols [ "MAILCOW_WHITE" ] "401": $ref: "#/components/responses/Unauthorized" /api/v1/add/global-filter: post: summary: Save a global Sieve filter description: >- Replaces the global Sieve prefilter or postfilter and restarts Dovecot. A script with errors is not saved. Messages: `global_filter_written`, `dovecot_restart_success`; errors `sieve_error`, `invalid_filter_type`, `global_filter_write_error`, `dovecot_restart_failed`. operationId: addGlobalFilter tags: - Global filters requestBody: content: application/json: schema: type: object properties: filter_type: type: string enum: - prefilter - postfilter description: Which global filter to replace script_data: type: string description: The Sieve script (CRLF and CR line ends become LF) required: - filter_type - script_data example: filter_type: postfilter script_data: |- require "fileinto"; if header :contains "X-Spam-Flag" "YES" { fileinto "Junk"; } responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/global_filters/all: get: summary: Get the global Sieve filters description: >- Returns the global Sieve prefilter and postfilter. operationId: getGlobalFilters tags: - Global filters responses: "200": description: Both scripts content: application/json: schema: $ref: "#/components/schemas/GlobalFilters" example: prefilter: | # global_sieve_before script # global_sieve_before -> user sieve_before (mailcow UI) -> user sieve_after (mailcow UI) -> global_sieve_after postfilter: |- # global_sieve_after script require "fileinto"; if header :contains "X-Spam-Flag" "YES" { fileinto "Junk"; } "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/global_filters/{filter_type}: get: summary: Get one global Sieve filter description: >- Returns the global Sieve prefilter or postfilter as a JSON string; `{}` when the script is empty. operationId: getGlobalFilter tags: - Global filters parameters: - name: filter_type in: path required: true description: Which global filter schema: type: string enum: - prefilter - postfilter example: prefilter responses: "200": description: The Sieve script content: application/json: schema: type: string example: | # global_sieve_before script # global_sieve_before -> user sieve_before (mailcow UI) -> user sieve_after (mailcow UI) -> global_sieve_after "401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/quota_notification: post: summary: Edit quota notification settings description: >- Saves sender, subject and template of the mails users get when their mailbox crosses 80 % and 95 % of its quota. Fields not sent become empty. The current values cannot be read through the API. Messages: `saved_settings`; errors `redis_error`. operationId: editQuotaNotification tags: - Quota notifications requestBody: content: application/json: schema: type: object properties: items: description: Ignored attr: type: object properties: sender: type: string description: Sender address (invalid address = empty) subject: type: string description: Subject html_tmpl: type: string description: HTML template (empty = the default template) required: - attr example: items: - quota_notification attr: sender: quota-warning@example.org subject: Quota warning html_tmpl: "" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/quota_notification_bcc: post: summary: Edit quota notification BCC of a domain description: >- Sets the addresses that get a copy of every quota warning of a domain; the list replaces the old one and cannot be read through the API. Admins and domain admins of the domain. Invalid addresses are left out, the others are saved. Messages: `saved_settings`; errors `goto_invalid`, `redis_error`. operationId: editQuotaNotificationBcc tags: - Quota notifications requestBody: content: application/json: schema: type: object properties: items: description: Ignored attr: type: object properties: domain: type: string description: Domain or alias domain bcc_rcpt: type: string description: Addresses, separated by space, comma, semicolon or newline active: type: [boolean, integer, string] description: 1 = send the copies; becomes 0 when no valid address is left required: - domain required: - attr example: items: - quota_bcc attr: domain: example.org bcc_rcpt: |- postmaster@example.org helpdesk@example.org active: "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/admin/all: get: summary: Get administrators description: Lists all administrators, without domain administrators and the API key account. operationId: getAdmins tags: - Administrators responses: "200": description: The administrators, `{}` if there are none content: application/json: schema: type: array items: $ref: "#/components/schemas/Admin" example: - username: admin tfa_active: 1 tfa_active_int: 1 active: 1 active_int: 1 created: "2026-09-21 10:23:08" attributes: force_tfa: "0" force_pw_update: "0" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/admin/{username}: get: summary: Get administrator description: Details of one administrator. operationId: getAdmin tags: - Administrators parameters: - name: username in: path required: true description: Username of the administrator schema: type: string example: admin responses: "200": description: The administrator, `{}` if there is no administrator of this name content: application/json: schema: $ref: "#/components/schemas/Admin" example: username: admin tfa_active: 0 tfa_active_int: 0 active: 1 active_int: 1 created: "2026-09-21 10:23:08" attributes: force_tfa: "0" force_pw_update: "0" "401": $ref: "#/components/responses/Unauthorized" /api/v1/add/admin: post: summary: Create administrator description: >- Creates an administrator. The username is stored in lowercase and must not be in use by an administrator or domain administrator. Without `active: 1` the account is disabled. Messages: `admin_added`; errors `object_exists`, `password_complexity`, `password_mismatch`. operationId: addAdmin tags: - Administrators requestBody: required: true content: application/json: schema: type: object properties: username: type: string description: Username (letters, digits, `_`, `.`, `-`; stored in lowercase) password: type: string description: Password, must match the password policy password2: type: string description: The password again active: type: [integer, string, boolean] description: 1 = the account can log in, 0 = disabled default: 0 required: - username - password - password2 example: username: admin2 password: "Rand0m-Passw0rd!" password2: "Rand0m-Passw0rd!" active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/admin: post: summary: Edit administrators description: >- Changes administrators. Fields not sent keep their value, but `force_tfa` and `force_pw_update` are reset to 0; an empty `password` keeps the password. FIDO2 keys are not moved on rename. The last active administrator cannot be deactivated. Messages: `admin_modified`; errors `username_invalid`, `password_mismatch`, `password_complexity`; warning `no_active_admin`. operationId: editAdmin tags: - Administrators requestBody: required: true content: application/json: schema: type: object properties: items: description: Username of the administrator, or a list of usernames oneOf: - type: string - type: array items: type: string attr: type: object properties: active: type: [integer, string, boolean] description: 1 = active, 0 = disabled username_new: type: string description: New username (letters, digits, `_`, `.`, `-`) password: type: string description: New password; empty or missing keeps the password password2: type: string description: The new password again force_tfa: type: [integer, string, boolean] description: 1 = the administrator must set up two-factor authentication at the next login default: 0 force_pw_update: type: [integer, string, boolean] description: 1 = the administrator must change the password at the next login default: 0 disable_tfa: type: [integer, string, boolean] description: Present (any value) = turn off two-factor authentication required: - items - attr example: items: - admin2 attr: active: 1 password: "N3w-Passw0rd!" password2: "N3w-Passw0rd!" force_pw_update: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/delete/admin: post: summary: Delete administrators description: >- Deletes administrators with their two-factor authentication and FIDO2 keys. Messages: `admin_removed`; error `username_invalid`. operationId: deleteAdmin tags: - Administrators requestBody: required: true content: application/json: schema: type: array description: Usernames of the administrators items: type: string example: - admin2 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/get/passwordpolicy: get: summary: Get password policy description: The password policy for mailboxes, administrators and domain administrators. operationId: getPasswordPolicy tags: - Password policy responses: "200": description: The policy content: application/json: schema: $ref: "#/components/schemas/PasswordPolicy" example: length: "8" chars: "1" special_chars: "0" lowerupper: "1" numbers: "1" "401": $ref: "#/components/responses/Unauthorized" /api/v1/get/passwordpolicy/html: get: summary: Get password policy as HTML description: >- The password policy as HTML snippet in the default language, as shown below password fields. operationId: getPasswordPolicyHtml tags: - Password policy responses: "200": description: The HTML snippet as a JSON string content: application/json: schema: type: string example:

- Minimum password length is 8
- Must contain at least one alphabetic character
- Must contain lowercase and uppercase characters
- Must contain at least one number

"401": $ref: "#/components/responses/Unauthorized" /api/v1/edit/passwordpolicy: post: summary: Edit password policy description: >- Changes the password policy; fields not sent keep their value. Existing passwords are not checked again. Messages: `password_policy_saved`. operationId: editPasswordPolicy tags: - Password policy requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: length: type: [integer, string] description: Minimum length; values below 3 keep the current length chars: type: [integer, string, boolean] description: 1 = at least one letter lowerupper: type: [integer, string, boolean] description: 1 = lowercase and uppercase letters special_chars: type: [integer, string, boolean] description: 1 = at least one character that is no letter or digit numbers: type: [integer, string, boolean] description: 1 = at least one digit required: - attr example: attr: length: 12 chars: 1 lowerupper: 1 special_chars: 0 numbers: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/reset-password-notification: post: summary: Edit password reset e-mail description: >- Sets the password reset e-mail sent to the recovery address of a mailbox. Fields not sent are saved as empty. With both templates empty the defaults are used; without sender and subject, password reset is off. Placeholders: `{{username}}`, `{{username2}}` (recovery address), `{{date}}`, `{{token_lifetime}}` (minutes), `{{hostname}}`, `{{link}}`. Messages: `saved_settings`. operationId: editPasswordResetNotification tags: - Password policy requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: from: type: string description: Sender address; an invalid address is saved as empty subject: type: string description: Subject text_tmpl: type: string description: Plain text template html_tmpl: type: string description: HTML template (the text template becomes its alternative part) required: - attr example: attr: from: noreply@example.org subject: Reset your password text_tmpl: "Hello {{username}}, open {{link}} within {{token_lifetime}} minutes to set a new password." html_tmpl: "

Hello {{username}},

Set a new password within {{token_lifetime}} minutes.

" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/app_links: post: summary: Edit app links description: >- Replaces the custom links of the Apps menu, sent as four lists of equal length. If the lengths differ, nothing is saved, but `app_links` is reported anyway. Empty lists remove all custom links. Messages: `app_links`. operationId: editAppLinks tags: - UI customization requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: app: type: array description: Names of the links items: type: string href: type: array description: URLs shown on the login page and to users without `user_href` items: type: string user_href: type: array description: URLs for logged-in accounts (`%u` = username); empty = `href` items: type: string hide: type: array description: Per link, `0` shows it on the login page, any other value (even `false`) hides it items: type: [string, integer, boolean] required: - attr example: attr: app: - Wiki - Webmail (Roundcube) href: - https://wiki.example.org - https://mail.example.org/rc/ user_href: - https://wiki.example.org - https://mail.example.org/rc/?_user=%u hide: - "0" - "1" responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/custom_login: post: summary: Edit login page options description: >- Sets the login page options. All four are replaced: a missing option counts as 0. Messages: `custom_login_modified`. operationId: editCustomLogin tags: - UI customization requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: hide_user_quicklink: type: [integer, string, boolean] description: 1 = hide the link to the user login page default: 0 hide_domainadmin_quicklink: type: [integer, string, boolean] description: 1 = hide the link to the domain administrator login page default: 0 hide_admin_quicklink: type: [integer, string, boolean] description: 1 = hide the link to the administrator login page default: 0 force_sso: type: [integer, string, boolean] description: 1 = show only the Single Sign-On button (needs an OIDC identity provider) default: 0 required: - attr example: attr: hide_user_quicklink: 0 hide_domainadmin_quicklink: 1 hide_admin_quicklink: 1 force_sso: 0 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/ip_check: post: summary: Edit IP check description: >- Turns the dashboard IP check on or off, which asks ipv4.mailcow.email and ipv6.mailcow.email for the public addresses. Messages: `ip_check_opt_in_modified`. operationId: editIpCheck tags: - UI customization requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: ip_check_opt_in: type: [integer, string, boolean] description: 1/true = enabled; anything else or missing = disabled default: 0 required: - attr example: attr: ip_check_opt_in: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/ui_texts: post: summary: Edit UI texts description: >- Sets the texts of the mailcow UI. All values are replaced: a missing one is saved as empty. Messages: `ui_texts`. operationId: editUiTexts tags: - UI customization requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: title_name: type: string description: Title of the browser window (plain text); empty = " - mail UI" main_name: type: string description: Name shown on the start page (plain text); empty = " - mail UI" apps_name: type: string description: Name of the "Apps" menu (plain text); empty = "Apps" help_text: type: string description: Help text below the login form (HTML) ui_footer: type: string description: Footer of every page (HTML) ui_announcement_text: type: string description: Announcement for all logged-in accounts and on the login page (HTML) ui_announcement_type: type: string enum: - info - warning - danger description: Style of the announcement; other values are saved as empty ui_announcement_active: type: [integer, string, boolean] description: Not empty and not 0 = show the announcement default: 0 required: - attr example: attr: title_name: Example Mail main_name: Example Mail apps_name: Apps help_text: "Questions? Write to support@example.org." ui_footer: "Imprint" ui_announcement_text: Maintenance on Saturday from 8 to 10 am. ui_announcement_type: warning ui_announcement_active: 1 responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/v1/edit/ui_theme: post: summary: Edit UI theme description: >- Selects the UI theme by its folder name in `data/web/css/themes/`. Messages: `ui_theme_modified`; error `ui_theme_invalid`. operationId: editUiTheme tags: - UI customization requestBody: required: true content: application/json: schema: type: object properties: attr: type: object properties: ui_theme: description: Folder name of the theme, empty = default theme; of a list only the first entry counts oneOf: - type: string - type: array items: type: string required: - attr example: attr: ui_theme: servercow responses: "200": $ref: "#/components/responses/WriteResult" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" tags: - name: Domains description: >- Domains, alias domains, domain templates, MTA-STS policies and domain-wide footers - name: Domain antispam policies description: Sender allow lists (whitelists) and deny lists (blacklists) of domains - name: Mailboxes description: Mailboxes, their templates, tags, ACLs and logins - name: Aliases description: You can manage aliases - name: Sync jobs description: Using Syncjobs you can sync your mails with other email servers - name: Logs description: Logs of the mailcow containers and the UI - name: Queue Manager description: Manage the postfix mail queue - name: Quarantine description: Check what emails went to quarantine - name: Fail2Ban description: Manage the Netfilter fail2ban options - name: DKIM description: Generate, import, copy and delete DKIM keys - name: Domain admin description: Domain administrators, their domains and ACLs - name: Single Sign-On description: Login tokens for domain administrators - name: Address Rewriting description: BCC maps and recipient maps - name: Outgoing TLS Policy Map Overrides description: TLS policies for outgoing connections to single destinations - name: oAuth Clients description: Clients that use mailcow as OAuth2 server - name: API Keys description: API keys; service keys from mailcow.conf are read-only - name: Groups description: Mailbox groups (distribution lists, send-as rights, templates) - name: Routing description: Sender-dependent transports (relay hosts) and transport maps for outgoing mail - name: Resources description: Bookable resources (rooms, equipment, groups) for SOGo - name: App Passwords description: Separate passwords of a mailbox for single clients and protocols - name: Status description: Containers, mail storage, host and version - name: Ratelimits description: Edit domain ratelimits - name: Cross-Origin Resource Sharing (CORS) description: Origins and methods that may call the API from a browser - name: Identity Provider description: >- External Identity Provider (Keycloak, OpenID Connect, LDAP): settings, identity sync and links of mailboxes - name: Mailbox user settings description: >- Settings a mailbox user changes on its own page (with the matching user ACL): time-limited aliases, spam score, TLS policy, tagged mail, Pushover. API keys can change them for any mailbox and must name the mailbox; a mailbox user only for its own. - name: Mailbox filters description: Sieve filters of mailboxes, managed by admins and domain admins - name: Mailbox antispam policies description: Sender allow and deny lists of mailboxes - name: Forwarding Hosts description: >- Hosts whose incoming mail is accepted unconditionally, e.g. servers that forward mail to mailcow - name: Rspamd description: Rspamd settings rules, global regex maps, presets and statistics - name: Global filters description: Global Sieve filters that run before and after the filters of the mailboxes, Sieve presets - name: Quota notifications description: Mails to users whose mailbox is nearly full - name: Administrators description: Administrator accounts - name: Password policy description: Password rules and the password reset e-mail - name: UI customization description: Texts, links, login page and theme of the mailcow UI