| The web administration supports for now the CRUD operations on the domains, the users, their mailboxes and their quotas, |
| managing mail repositories, performing {backend-name} migrations, and much more, as described in the following sections. |
| |
| *WARNING*: This API allow authentication only via the use of JWT. If not |
| configured with JWT, an administrator should ensure an attacker can not |
| use this API. |
| |
| By the way, some endpoints are not filtered by authentication. Those endpoints are not related to data stored in James, |
| for example: Swagger documentation & James health checks. |
| |
| In case of any error, the system will return an error message which is |
| json format like this: |
| |
| .... |
| { |
| statusCode: <error_code>, |
| type: <error_type>, |
| message: <the_error_message> |
| cause: <the_detail_message_from_throwable> |
| } |
| .... |
| |
| Also be aware that, in case things go wrong, all endpoints might return |
| a 500 internal error (with a JSON body formatted as exposed above). To |
| avoid information duplication, this is omitted on endpoint specific |
| documentation. |
| |
| Finally, please note that in case of a malformed URL the 400 bad request |
| response will contain an HTML body. |
| |
| == HealthCheck |
| |
| === Check all components |
| |
| This endpoint is simple for now and is just returning the http status |
| code corresponding to the state of checks (see below). The user has to |
| check in the logs in order to have more information about failing |
| checks. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck |
| .... |
| |
| Will return a list of healthChecks execution result, with an aggregated |
| result: |
| |
| .... |
| { |
| "status": "healthy", |
| "checks": [ |
| { |
| "componentName": "{backend-name} backend", |
| "escapedComponentName": "{backend-name}%20backend", |
| "status": "healthy" |
| "cause": null |
| } |
| ] |
| } |
| .... |
| |
| *status* field can be: |
| |
| * *healthy*: Component works normally |
| * *degraded*: Component works in degraded mode. Some non-critical |
| services may not be working, or latencies are high, for example. Cause |
| contains explanations. |
| * *unhealthy*: The component is currently not working. Cause contains |
| explanations. |
| |
| Supported health checks include: |
| |
| * *{backend-name} backend*: {backend-name} storage. |
| * *OpenSearch Backend*: OpenSearch storage. |
| * *EventDeadLettersHealthCheck* |
| * *Guice application lifecycle* |
| * *JPA Backend*: JPA storage. |
| * *MailReceptionCheck* We rely on a configured user, send an email to him and |
| assert that the email is well received, and can be read within the given configured |
| period. Unhealthy means that the email could not be received before reacing the timeout. |
| * *MessageFastViewProjection* Health check of the component storing JMAP properties |
| which are fast to retrieve. Those properties are computed in advance |
| from messages and persisted in order to archive a better performance. |
| There are some latencies between a source update and its projections |
| updates. Incoherency problems arise when reads are performed in this |
| time-window. We piggyback the projection update on missed JMAP read in |
| order to decrease the outdated time window for a given entry. The health |
| is determined by the ratio of missed projection reads. (lower than 10% |
| causes `degraded`) |
| * *RabbitMQ backend*: RabbitMQ messaging. |
| |
| Response codes: |
| |
| * 200: All checks have answered with a Healthy or Degraded status. James |
| services can still be used. |
| * 503: At least one check have answered with a Unhealthy status |
| |
| Additional query parameters are supported: |
| |
| - `strict` allows you enable the strict mode. In this mode, if any checks have the result of Degraded or Unhealthy status, the response code will be 503. If omitted, degraded checks would be reported with status code 200. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck?strict |
| .... |
| |
| === Check specific components |
| |
| Performs health checks for the given components. Components are |
| referenced by their URL encoded names. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck?check=HealthCheck1&check=HealthCheck%20two |
| .... |
| |
| Will return a list of healthChecks execution result, with an aggregated |
| result: |
| |
| .... |
| { |
| "status": "healthy", |
| "checks": [ |
| { |
| "componentName": "HealthCheck1", |
| "escapedComponentName": "HealthCheck1", |
| "status": "healthy" |
| "cause": null |
| }, |
| { |
| "componentName": "HealthCheck two", |
| "escapedComponentName": "HealthCheck%20two", |
| "status": "healthy" |
| "cause": null |
| } |
| ] |
| } |
| .... |
| |
| *status* field can be: |
| |
| * *healthy*: Component works normally |
| * *degraded*: Component works in degraded mode. Some non-critical |
| services may not be working, or latencies are high, for example. Cause |
| contains explanations. |
| * *unhealthy*: The component is currently not working. Cause contains |
| explanations. |
| |
| Response codes: |
| |
| * 200: All checks have answered with a Healthy or Degraded status. James |
| services can still be used. |
| * 503: At least one check have answered with a Unhealthy status |
| |
| Additional query parameters are supported: |
| |
| - `strict` allows you enable the strict mode. In this mode, if any checks have the result of Degraded or Unhealthy status, the response code will be 503. If omitted, degraded checks would be reported with status code 200. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck?strict&check=HealthCheck1&check=HealthCheck%20two |
| .... |
| |
| === Check single component |
| |
| Performs a health check for the given component. The component is |
| referenced by its URL encoded name. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck/checks/{backend-name}%20backend |
| .... |
| |
| Will return the component’s name, the component’s escaped name, the |
| health status and a cause. |
| |
| .... |
| { |
| "componentName": "{backend-name} backend", |
| "escapedComponentName": "{backend-name}%20backend", |
| "status": "healthy" |
| "cause": null |
| } |
| .... |
| |
| Response codes: |
| |
| * 200: The check has answered with a Healthy or Degraded status. |
| * 404: A component with the given name was not found. |
| * 503: The check has answered with an Unhealthy status. |
| |
| Additional query parameters are supported: |
| |
| - `strict` allows you enable the strict mode. In this mode, if any checks have the result of Degraded or Unhealthy status, the response code will be 503. If omitted, degraded checks would be reported with status code 200. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck/checks/{backend-name}%20backend?strict |
| .... |
| |
| === List all health checks |
| |
| This endpoint lists all the available health checks. |
| |
| .... |
| curl -XGET http://ip:port/healthcheck/checks |
| .... |
| |
| Will return the list of all available health checks. |
| |
| .... |
| [ |
| { |
| "componentName": "{backend-name} backend", |
| "escapedComponentName": "{backend-name}%20backend" |
| } |
| ] |
| .... |
| |
| Response codes: |
| |
| * 200: List of available health checks |
| |
| == Task management |
| |
| Some webadmin features schedule tasks. The task management API allow to |
| monitor and manage the execution of the following tasks. |
| |
| Note that the `taskId` used in the following APIs is returned by other |
| WebAdmin APIs scheduling tasks. |
| |
| === Getting a task details |
| |
| .... |
| curl -XGET http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2 |
| .... |
| |
| An Execution Report will be returned: |
| |
| .... |
| { |
| "submitDate": "2017-12-27T15:15:24.805+0700", |
| "startedDate": "2017-12-27T15:15:24.809+0700", |
| "completedDate": "2017-12-27T15:15:24.815+0700", |
| "cancelledDate": null, |
| "failedDate": null, |
| "taskId": "3294a976-ce63-491e-bd52-1b6f465ed7a2", |
| "additionalInformation": {}, |
| "status": "completed", |
| "type": "type-of-the-task" |
| } |
| .... |
| |
| Note that: |
| |
| * `status` can have the value: |
| ** `waiting`: The task is scheduled but its execution did not start yet |
| ** `inProgress`: The task is currently executed |
| ** `cancelled`: The task had been cancelled |
| ** `completed`: The task execution is finished, and this execution is a |
| success |
| ** `failed`: The task execution is finished, and this execution is a |
| failure |
| * `additionalInformation` is a task specific object giving additional |
| information and context about that task. The structure of this |
| `additionalInformation` field is provided along the specific task |
| submission endpoint. |
| |
| Response codes: |
| |
| * 200: The specific task was found and the execution report exposed |
| above is returned |
| * 400: Invalid task ID |
| * 404: Task ID was not found |
| |
| === Awaiting a task |
| |
| One can await the end of a task, then receive its final execution |
| report. |
| |
| That feature is especially usefully for testing purpose but still can |
| serve real-life scenario. |
| |
| .... |
| curl -XGET http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2/await?timeout=duration |
| .... |
| |
| An Execution Report will be returned. |
| |
| `timeout` is optional. By default it is set to 365 days (the maximum |
| value). The expected value is expressed in the following format: |
| `Nunit`. `N` should be strictly positive. `unit` could be either in the |
| short form (`s`, `m`, `h`, etc.), or in the long form (`day`, `week`, |
| `month`, etc.). |
| |
| Examples: |
| |
| * `30s` |
| * `5m` |
| * `7d` |
| * `1y` |
| |
| Response codes: |
| |
| * 200: The specific task was found and the execution report exposed |
| above is returned |
| * 400: Invalid task ID or invalid timeout |
| * 404: Task ID was not found |
| * 408: The timeout has been reached |
| |
| === Cancelling a task |
| |
| You can cancel a task by calling: |
| |
| .... |
| curl -XDELETE http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2 |
| .... |
| |
| Response codes: |
| |
| * 204: Task had been cancelled |
| * 400: Invalid task ID |
| |
| === Listing tasks |
| |
| A list of all tasks can be retrieved: |
| |
| .... |
| curl -XGET http://ip:port/tasks |
| .... |
| |
| Will return a list of Execution reports |
| |
| One can filter the above results by status. For example: |
| |
| .... |
| curl -XGET http://ip:port/tasks?status=inProgress |
| .... |
| |
| Will return a list of Execution reports that are currently in progress. This list is sorted by |
| reverse submitted date (recent tasks goes first). |
| |
| Response codes: |
| |
| * 200: A list of corresponding tasks is returned |
| * 400: Invalid status value |
| |
| Additional optional task parameters are supported: |
| |
| - `status` one of `waiting`, `inProgress`, `canceledRequested`, `completed`, `canceled`, `failed`. Only |
| tasks with the given status are returned. |
| - `type`: only tasks with the given type are returned. |
| - `submittedBefore`: Date. Returns only tasks submitted before this date. |
| - `submittedAfter`: Date. Returns only tasks submitted after this date. |
| - `startedBefore`: Date. Returns only tasks started before this date. |
| - `startedAfter`: Date. Returns only tasks started after this date. |
| - `completedBefore`: Date. Returns only tasks completed before this date. |
| - `completedAfter`: Date. Returns only tasks completed after this date. |
| - `failedBefore`: Date. Returns only tasks failed before this date. |
| - `failedAfter`: Date. Returns only tasks faield after this date. |
| - `offset`: Integer, number of tasks to skip in the response. Useful for paging. |
| - `limit`: Integer, maximum number of tasks to return in one call |
| |
| Example of date format: `2023-04-15T07:23:27.541254+07:00` and `2023-04-15T07%3A23%3A27.541254%2B07%3A00` once URL encoded. |
| |
| === Cleaning up old tasks |
| |
| .... |
| curl -XDELETE http://ip:port/tasks?olderThan=30day |
| .... |
| |
| Will start a task which will cleanup old tasks still referenced in the TaskManager. |
| |
| === Endpoints returning a task |
| |
| Many endpoints do generate a task. |
| |
| Example: |
| |
| .... |
| curl -XPOST /endpoint?action={action} |
| .... |
| |
| The response to these requests will be the scheduled `taskId` : |
| |
| .... |
| {"taskId":"5641376-02ed-47bd-bcc7-76ff6262d92a"} |
| .... |
| |
| Positionned headers: |
| |
| * Location header indicates the location of the resource associated with |
| the scheduled task. Example: |
| |
| .... |
| Location: /tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2 |
| .... |
| |
| Response codes: |
| |
| * 201: Task generation succeeded. Corresponding task id is returned. |
| * Other response codes might be returned depending on the endpoint |
| |
| The additional information returned depends on the scheduled task type |
| and is documented in the endpoint documentation. |
| |
| == Administrating domains |
| |
| === Create a domain |
| |
| .... |
| curl -XPUT http://ip:port/domains/domainToBeCreated |
| .... |
| |
| Resource name domainToBeCreated: |
| |
| * can not be null or empty |
| * can not contain `@' |
| * can not be more than 255 characters |
| * can not contain `/' |
| |
| Response codes: |
| |
| * 204: The domain was successfully added |
| * 400: The domain name is invalid |
| |
| === Delete a domain |
| |
| .... |
| curl -XDELETE http://ip:port/domains/{domainToBeDeleted} |
| .... |
| |
| Note: Deletion of an auto-detected domain, default domain or of an |
| auto-detected ip is not supported. We encourage you instead to review |
| your https://james.apache.org/server/config-domainlist.html[domain list |
| configuration]. |
| |
| Response codes: |
| |
| * 204: The domain was successfully removed |
| |
| === Test if a domain exists |
| |
| .... |
| curl -XGET http://ip:port/domains/{domainName} |
| .... |
| |
| Response codes: |
| |
| * 204: The domain exists |
| * 404: The domain does not exist |
| |
| === Get the list of domains |
| |
| .... |
| curl -XGET http://ip:port/domains |
| .... |
| |
| Possible response: |
| |
| .... |
| ["domain1", "domain2"] |
| .... |
| |
| Response codes: |
| |
| * 200: The domain list was successfully retrieved |
| |
| === Get the list of users for a domain |
| |
| .... |
| curl -XGET http://ip:port/domains/domain.tld/users |
| .... |
| |
| Will return the list of users for this domain: |
| |
| .... |
| [ |
| "btellier@domain.tld", |
| ... |
| ] |
| .... |
| |
| * 200: The domain aliases was successfully retrieved |
| * 400: domain.tld has an invalid syntax |
| * 404: domain.tld is not part of handled domains and does |
| not have local domains as aliases. |
| |
| Only supported when virtualHosting is enabled. |
| |
| === Get the list of aliases for a domain |
| |
| .... |
| curl -XGET http://ip:port/domains/destination.domain.tld/aliases |
| .... |
| |
| Possible response: |
| |
| .... |
| [ |
| {"source": "source1.domain.tld"}, |
| {"source": "source2.domain.tld"} |
| ] |
| .... |
| |
| When sending an email to an email address having `source1.domain.tld` or |
| `source2.domain.tld` as a domain part (example: |
| `user@source1.domain.tld`), then the domain part will be rewritten into |
| destination.domain.tld (so into `user@destination.domain.tld`). |
| |
| Response codes: |
| |
| * 200: The domain aliases was successfully retrieved |
| * 400: destination.domain.tld has an invalid syntax |
| * 404: destination.domain.tld is not part of handled domains and does |
| not have local domains as aliases. |
| |
| === Create an alias for a domain |
| |
| To create a domain alias execute the following query: |
| |
| .... |
| curl -XPUT http://ip:port/domains/destination.domain.tld/aliases/source.domain.tld |
| .... |
| |
| When sending an email to an email address having `source.domain.tld` as |
| a domain part (example: `user@source.domain.tld`), then the domain part |
| will be rewritten into `destination.domain.tld` (so into |
| `user@destination.domain.tld`). |
| |
| Response codes: |
| |
| * 204: The redirection now exists |
| * 400: `source.domain.tld` or `destination.domain.tld` have an invalid |
| syntax |
| * 400: `source, domain` and `destination domain` are the same |
| * 404: `source.domain.tld` are not part of handled domains. |
| |
| Be aware that no checks to find possible loops that would result of this creation will be performed. |
| |
| === Delete an alias for a domain |
| |
| To delete a domain alias execute the following query: |
| |
| .... |
| curl -XDELETE http://ip:port/domains/destination.domain.tld/aliases/source.domain.tld |
| .... |
| |
| When sending an email to an email address having `source.domain.tld` as |
| a domain part (example: `user@source.domain.tld`), then the domain part |
| will be rewritten into `destination.domain.tld` (so into |
| `user@destination.domain.tld`). |
| |
| Response codes: |
| |
| * 204: The redirection now no longer exists |
| * 400: `source.domain.tld` or destination.domain.tld have an invalid |
| syntax |
| * 400: source, domain and destination domain are the same |
| * 404: `source.domain.tld` are not part of handled domains. |
| |
| === Delete all users data of a domain |
| |
| .... |
| curl -XPOST http://ip:port/domains/{domainToBeUsed}?action=deleteData |
| .... |
| |
| Would create a task that deletes data of all users of the domain. |
| |
| [More details about endpoints returning a task](#_endpoints_returning_a_task). |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The scheduled task will have the following type `DeleteUsersDataOfDomainTask` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type": "DeleteUsersDataOfDomainTask", |
| "domain": "domain.tld", |
| "successfulUsersCount": 2, |
| "failedUsersCount": 1, |
| "failedUsers": ["faileduser@domain.tld"], |
| "timestamp": "2023-05-22T08:52:47.076261Z" |
| } |
| .... |
| |
| Notes: `failedUsers` only lists maximum 100 failed users. |
| |
| == Administrating users |
| |
| === Create a user |
| |
| .... |
| curl -XPUT http://ip:port/users/usernameToBeUsed \ |
| -d '{"password":"passwordToBeUsed"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Resource name usernameToBeUsed representing valid users, hence it should |
| match the criteria at xref:{xref-base}/configure/usersrepository.adoc[User Repositories documentation] |
| |
| Response codes: |
| |
| * 204: The user was successfully created |
| * 400: The user name or the payload is invalid |
| * 409: The user name already exists |
| |
| Note: If the user exists already, its password cannot be updated using this. |
| If you want to update a user's password, please have a look at *Update a user password* below. |
| |
| === Updating a user password |
| |
| .... |
| curl -XPUT http://ip:port/users/usernameToBeUsed?force \ |
| -d '{"password":"passwordToBeUsed"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Response codes: |
| |
| - 204: The user's password was successfully updated |
| - 400: The user name or the payload is invalid |
| |
| This also can be used to create a new user. |
| |
| === Verifying a user password |
| |
| .... |
| curl -XPOST http://ip:port/users/usernameToBeUsed/verify \ |
| -d '{"password":"passwordToBeVerified"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Response codes: |
| |
| - 204: The user's password was correct |
| - 401: Wrong password or user does not exist |
| - 400: The user name or the payload is invalid |
| |
| This intentionally treats non-existing users as unauthenticated, to prevent a username oracle attack. |
| |
| === Testing a user existence |
| |
| .... |
| curl -XHEAD http://ip:port/users/usernameToBeUsed |
| .... |
| |
| Resource name ``usernameToBeUsed'' represents a valid user, hence it |
| should match the criteria at xref:{xref-base}/configure/usersrepository.adoc[User Repositories documentation] |
| |
| Response codes: |
| |
| * 200: The user exists |
| * 400: The user name is invalid |
| * 404: The user does not exist |
| |
| === Deleting a user |
| |
| .... |
| curl -XDELETE http://ip:port/users/{userToBeDeleted} |
| .... |
| |
| Response codes: |
| |
| * 204: The user was successfully deleted |
| |
| === Retrieving the user list |
| |
| .... |
| curl -XGET http://ip:port/users |
| .... |
| |
| The answer looks like: |
| |
| .... |
| [{"username":"username@domain-jmapauthentication.tld"},{"username":"username@domain.tld"}] |
| .... |
| |
| Response codes: |
| |
| * 200: The user name list was successfully retrieved |
| |
| Additional query parameters are supported: |
| |
| - `hasNoMailboxes` allows you to select users who don't have any mailboxes (also means that they have never logged in and received any emails). |
| .... |
| curl -XGET http://ip:port/users?hasNoMailboxes |
| .... |
| |
| - `hasNotAllSystemMailboxes` allows you to select users who don't have enough system mailboxes (also means that they have never logged in but received some emails). |
| .... |
| curl -XGET http://ip:port/users?hasNotAllSystemMailboxes |
| .... |
| |
| === Retrieving the list of allowed `From` headers for a given user |
| |
| This endpoint allows to know which From headers a given user is allowed to use when sending mails. |
| |
| .... |
| curl -XGET http://ip:port/users/givenUser/allowedFromHeaders |
| .... |
| |
| The answer looks like: |
| |
| .... |
| ["user@domain.tld","alias@domain.tld"] |
| .... |
| |
| Response codes: |
| |
| * 200: The list was successfully retrieved |
| * 400: The user is invalid |
| * 404: The user is unknown |
| |
| === Add a delegated user of a base user |
| |
| .... |
| curl -XPUT http://ip:port/users/baseUser/authorizedUsers/delegatedUser |
| .... |
| |
| Response codes: |
| |
| * 200: Addition of the delegated user succeeded |
| * 404: The base user does not exist |
| * 400: The delegated user does not exist |
| |
| Note: Delegation is only available on top of {backend-name} products and not implemented yet on top of JPA backends. |
| |
| === Remove a delegated user of a base user |
| |
| .... |
| curl -XDELETE http://ip:port/users/baseUser/authorizedUsers/delegatedUser |
| .... |
| |
| Response codes: |
| |
| * 200: Removal of the delegated user succeeded |
| * 404: The base user does not exist |
| * 400: The delegated user does not exist |
| |
| Note: Delegation is only available on top of {backend-name} products and not implemented yet on top of JPA backends. |
| |
| === Retrieving the list of delegated users of a base user |
| |
| .... |
| curl -XGET http://ip:port/users/baseUser/authorizedUsers |
| .... |
| |
| The answer looks like: |
| |
| .... |
| ["alice@domain.tld","bob@domain.tld"] |
| .... |
| |
| Response codes: |
| |
| * 200: The list was successfully retrieved |
| * 404: The base user does not exist |
| |
| Note: Delegation is only available on top of {backend-name} products and not implemented yet on top of JPA backends. |
| |
| === Remove all delegated users of a base user |
| |
| .... |
| curl -XDELETE http://ip:port/users/baseUser/authorizedUsers |
| .... |
| |
| Response codes: |
| |
| * 200: Removal of the delegated users succeeded |
| * 404: The base user does not exist |
| |
| Note: Delegation is only available on top of {backend-name} products and not implemented yet on top of JPA backends. |
| |
| === Change a username |
| |
| .... |
| curl -XPOST http://ip:port/users/oldUser/rename/newUser?action=rename |
| .... |
| |
| Would migrate account data from `oldUser` to `newUser`. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Implemented migration steps are: |
| |
| - `ForwardUsernameChangeTaskStep`: creates forward from old user to new user and migrates existing forwards |
| - `FilterUsernameChangeTaskStep`: migrates users filtering rules |
| - `DelegationUsernameChangeTaskStep`: migrates delegations where the impacted user is either delegatee or delegator |
| - `MailboxUsernameChangeTaskStep`: migrates mailboxes belonging to the old user to the account of the new user. It also |
| migrates user's mailbox subscriptions. |
| - `ACLUsernameChangeTaskStep`: migrates ACLs on mailboxes the migrated user has access to and updates subscriptions accordingly. |
| - `QuotaUsernameChangeTaskStep`: migrates quotas user from old user to new user. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. If you encounter the error "'oldUser' parameter should be an existing user," please note that this validation can be bypassed by specifying the `force` query parameter. |
| |
| The `fromStep` query parameter allows skipping previous steps, allowing to resume the username change from a failed step. |
| |
| The scheduled task will have the following type `UsernameChangeTask` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type": "UsernameChangeTask", |
| "oldUser": "jessy.jones@domain.tld", |
| "newUser": "jessy.smith@domain.tld", |
| "status": { |
| "A": "DONE", |
| "B": "FAILED", |
| "C": "ABORTED" |
| }, |
| "fromStep": null, |
| "timestamp": "2023-02-17T02:54:01.246477Z" |
| } |
| .... |
| |
| Valid status includes: |
| |
| - `SKIPPED`: bypassed via `fromStep` setting |
| - `WAITING`: Awaits execution |
| - `IN_PROGRESS`: Currently executed |
| - `FAILED`: Error encountered while executing this step. Check the logs. |
| - `ABORTED`: Won't be executed because of previous step failures. |
| |
| === Delete data of a user |
| |
| .... |
| curl -XPOST http://ip:port/users/usernameToBeUsed?action=deleteData |
| .... |
| |
| Would create a task that deletes data of the user. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning a task]. |
| |
| Implemented deletion steps are: |
| |
| - `RecipientRewriteTableUserDeletionTaskStep`: deletes all rewriting rules related to this user. |
| - `FilterUserDeletionTaskStep`: deletes all filters belonging to the user. |
| - `DelegationUserDeletionTaskStep`: deletes all delegations from / to the user. |
| - `MailboxUserDeletionTaskStep`: deletes mailboxes of this user, all ACLs of this user, as well as his subscriptions. |
| - `WebPushUserDeletionTaskStep`: deletes push data registered for this user. |
| - `IdentityUserDeletionTaskStep`: deletes identities registered for this user. |
| - `VacationUserDeletionTaskStep`: deletes vacations registered for this user. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The `fromStep` query parameter allows skipping previous steps, allowing to resume the user data deletion from a failed step. |
| |
| The scheduled task will have the following type `DeleteUserDataTask` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type": "DeleteUserDataTask", |
| "username": "jessy.jones@domain.tld", |
| "status": { |
| "A": "DONE", |
| "B": "FAILED", |
| "C": "ABORTED" |
| }, |
| "fromStep": null, |
| "timestamp": "2023-02-17T02:54:01.246477Z" |
| } |
| .... |
| |
| Valid status includes: |
| |
| - `SKIPPED`: bypassed via `fromStep` setting |
| - `WAITING`: Awaits execution |
| - `IN_PROGRESS`: Currently executed |
| - `FAILED`: Error encountered while executing this step. Check the logs. |
| - `ABORTED`: Won't be executed because of previous step failures. |
| |
| === Retrieving the user identities |
| |
| .... |
| curl -XGET http://ip:port/users/{baseUser}/identities?default=true |
| .... |
| |
| API to get the list of identities of a user |
| |
| The response will look like: |
| |
| ``` |
| [ |
| { |
| "name":"identity name 1", |
| "email":"bob@domain.tld", |
| "id":"4c039533-75b9-45db-becc-01fb0e747aa8", |
| "mayDelete":true, |
| "textSignature":"textSignature 1", |
| "htmlSignature":"htmlSignature 1", |
| "sortOrder":1, |
| "bcc":[ |
| { |
| "emailerName":"bcc name 1", |
| "mailAddress":"bcc1@domain.org" |
| } |
| ], |
| "replyTo":[ |
| { |
| "emailerName":"reply name 1", |
| "mailAddress":"reply1@domain.org" |
| } |
| ] |
| } |
| ] |
| ``` |
| |
| Query parameters: |
| |
| * default: (Optional) allows getting the default identity of a user. In order to do that: `default=true` |
| |
| Response codes: |
| |
| * 200: The list was successfully retrieved |
| * 400: The user is invalid |
| * 404: The user is unknown or the default identity can not be found. |
| |
| The optional `default` query parameter allows getting the default identity of a user. |
| In order to do that: `default=true` |
| |
| The web-admin server will return `404` response code when the default identity can not be found. |
| |
| === Creating a JMAP user identity |
| |
| API to create a new JMAP user identity |
| .... |
| curl -XPOST http://ip:port/users/{username}/identities \ |
| -d '{ |
| "name": "Bob", |
| "email": "bob@domain.tld", |
| "mayDelete": true, |
| "htmlSignature": "a html signature", |
| "textSignature": "a text signature", |
| "bcc": [{ |
| "email": "boss2@domain.tld", |
| "name": "My Boss 2" |
| }], |
| "replyTo": [{ |
| "email": "boss@domain.tld", |
| "name": "My Boss" |
| }], |
| "sortOrder": 0 |
| }' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Response codes: |
| |
| * 201: The new identity was successfully created |
| * 404: The username is unknown |
| * 400: The payload is invalid |
| |
| Resource name ``username'' represents a valid user |
| |
| === Updating a JMAP user identity |
| |
| API to update an exist JMAP user identity |
| .... |
| curl -XPUT http://ip:port/users/{username}/identities/{identityId} \ |
| -d '{ |
| "name": "Bob", |
| "htmlSignature": "a html signature", |
| "textSignature": "a text signature", |
| "bcc": [{ |
| "email": "boss2@domain.tld", |
| "name": "My Boss 2" |
| }], |
| "replyTo": [{ |
| "email": "boss@domain.tld", |
| "name": "My Boss" |
| }], |
| "sortOrder": 1 |
| }' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Response codes: |
| |
| * 204: The identity were successfully updated |
| * 404: The username is unknown |
| * 400: The payload is invalid |
| |
| Resource name ``username'' represents a valid user |
| Resource name ``identityId'' represents a exist user identity |
| |
| == Administrating vacation settings |
| |
| === Get vacation settings |
| |
| .... |
| curl -XGET http://ip:port/vacation/usernameToBeUsed |
| .... |
| |
| Resource name usernameToBeUsed representing valid users, hence it should |
| match the criteria at xref:{xref-base}/configure/usersrepository.adoc[User Repositories documentation] |
| |
| The response will look like this: |
| |
| .... |
| { |
| "enabled": true, |
| "fromDate": "2021-09-20T10:00:00Z", |
| "toDate": "2021-09-27T18:00:00Z", |
| "subject": "Out of office", |
| "textBody": "I am on vacation, will be back soon.", |
| "htmlBody": "<p>I am on vacation, will be back soon.</p>" |
| } |
| .... |
| |
| Response codes: |
| |
| * 200: The vacation settings were successfully retrieved |
| * 404: The user name is unknown |
| |
| === Update vacation settings |
| |
| .... |
| curl -XPOST http://ip:port/vacation/usernameToBeUsed |
| .... |
| |
| Request body must be a JSON structure as described above. |
| |
| If any field is not set in the request, the corresponding field in the existing vacation message is left unchanged. |
| |
| Response codes: |
| |
| * 204: The vacation settings were successfully updated |
| * 404: The user name is unknown |
| * 400: The payload is invalid |
| |
| === Delete vacation settings |
| |
| .... |
| curl -XDELETE http://ip:port/vacation/usernameToBeUsed |
| .... |
| |
| For convenience, this disables and clears the existing vacation settings of the user. |
| |
| Response codes: |
| |
| * 204: The vacation settings were successfully disabled |
| * 404: The user name is unknown |
| |
| == Administrating mailboxes |
| |
| === All mailboxes |
| |
| Several actions can be performed on the server mailboxes. |
| |
| Request pattern is: |
| |
| .... |
| curl -XPOST /mailboxes?action={action1},... |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The kind of task scheduled depends on the action parameter. See below |
| for details. |
| |
| |
| ==== Recomputing Global JMAP fast message view projection |
| |
| Message fast view projection stores message properties expected to be |
| fast to fetch but are actually expensive to compute, in order for |
| GetMessages operation to be fast to execute for these properties. |
| |
| These projection items are asynchronously computed on mailbox events. |
| |
| You can force the full projection recomputation by calling the following |
| endpoint: |
| |
| .... |
| curl -XPOST /mailboxes?task=recomputeFastViewProjectionItems |
| .... |
| |
| Will schedule a task for recomputing the fast message view projection |
| for all mailboxes. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed, per |
| second. Defaults to 10. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters. |
| |
| Example: |
| |
| .... |
| curl -XPOST /mailboxes?task=recomputeFastViewProjectionItems&messagesPerSecond=20 |
| .... |
| |
| The scheduled task will have the following type |
| `RecomputeAllFastViewProjectionItemsTask` and the following |
| `additionalInformation`: |
| |
| .... |
| { |
| "type":"RecomputeAllPreviewsTask", |
| "processedUserCount": 3, |
| "processedMessageCount": 3, |
| "failedUserCount": 2, |
| "failedMessageCount": 1, |
| "runningOptions": { |
| "messagesPerSecond":20 |
| } |
| } |
| .... |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| ==== Populate email query view |
| |
| Email query view is an optional projection to offload common JMAP `Email/query` requests used for listing mails on {backend-name} |
| and not on the search index thus improving the overall reliability / performance on this operation. |
| |
| These projection items are asynchronously computed on mailbox events. |
| |
| You can populate this projection with the following request: |
| |
| .... |
| curl -XPOST /mailboxes?task=populateEmailQueryView |
| .... |
| |
| Will schedule a task for recomputing the fast message view projection |
| for all mailboxes. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed, per |
| second. Defaults to 10. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters. |
| |
| Example: |
| |
| .... |
| curl -XPOST /mailboxes?task=populateEmailQueryView&messagesPerSecond=20 |
| .... |
| |
| The scheduled task will have the following type |
| `PopulateEmailQueryViewTask` and the following |
| `additionalInformation`: |
| |
| .... |
| { |
| "type":"PopulateEmailQueryViewTask", |
| "processedUserCount": 3, |
| "processedMessageCount": 3, |
| "failedUserCount": 2, |
| "failedMessageCount": 1, |
| "runningOptions": { |
| "messagesPerSecond":20 |
| } |
| } |
| .... |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| ==== Recomputing {backend-name} filtering projection |
| |
| You can force the reset of the {backend-name} filtering projection by calling the following |
| endpoint: |
| |
| .... |
| curl -XPOST /mailboxes?task=populateFilteringProjection |
| .... |
| |
| Will schedule a task. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| The scheduled task will have the following type |
| `PopulateFilteringProjectionTask` and the following |
| `additionalInformation`: |
| |
| .... |
| { |
| "type":"RecomputeAllPreviewsTask", |
| "processedUserCount": 3, |
| "failedUserCount": 2 |
| } |
| .... |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| ==== ReIndexing action |
| |
| Be also aware of the limits of this API: |
| |
| Warning: During the re-indexing, the result of search operations might |
| be altered. |
| |
| Warning: Canceling this task should be considered unsafe as it will |
| leave the currently reIndexed mailbox as partially indexed. |
| |
| Warning: While we have been trying to reduce the inconsistency window to |
| a maximum (by keeping track of ongoing events), concurrent changes done |
| during the reIndexing might be ignored. |
| |
| ===== ReIndexing all mails |
| |
| .... |
| curl -XPOST http://ip:port/mailboxes?task=reIndex |
| .... |
| |
| Will schedule a task for reIndexing all the mails stored on this James |
| server. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed per |
| second. Default is 50. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter. |
| |
| An admin can also specify the reindexing mode it wants to use when |
| running the task: |
| |
| * `mode` the reindexing mode used. There are 2 modes for the moment: |
| ** `rebuildAll` allows to rebuild all indexes. This is the default mode. |
| ** `fixOutdated` will check for outdated indexed document and reindex |
| only those. |
| |
| This optional parameter must be passed as query parameter. |
| |
| It’s good to note as well that there is a limitation with the |
| `fixOutdated` mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed `expunged` operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed). |
| |
| Example: |
| |
| curl -XPOST http://ip:port/mailboxes?task=reIndex&messagesPerSecond=200&mode=rebuildAll |
| |
| The scheduled task will have the following type `full-reindexing` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"full-reindexing", |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"REBUILD_ALL" |
| }, |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12", "23" ], |
| "messageFailures": [ |
| { |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| } |
| .... |
| |
| ===== Fixing previously failed ReIndexing |
| |
| Will schedule a task for reIndexing all the mails which had failed to be |
| indexed from the ReIndexingAllMails task. |
| |
| Given `bbdb69c9-082a-44b0-a85a-6e33e74287a5` being a `taskId` generated |
| for a reIndexing tasks |
| |
| .... |
| curl -XPOST 'http://ip:port/mailboxes?task=reIndex&reIndexFailedMessagesOf=bbdb69c9-082a-44b0-a85a-6e33e74287a5' |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed per |
| second. Default is 50. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter. |
| |
| An admin can also specify the reindexing mode it wants to use when |
| running the task: |
| |
| * `mode` the reindexing mode used. There are 2 modes for the moment: |
| ** `rebuildAll` allows to rebuild all indexes. This is the default mode. |
| ** `fixOutdated` will check for outdated indexed document and reindex |
| only those. |
| |
| This optional parameter must be passed as query parameter. |
| |
| It’s good to note as well that there is a limitation with the |
| `fixOutdated` mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed `expunged` operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed). |
| |
| Example: |
| |
| .... |
| curl -XPOST http://ip:port/mailboxes?task=reIndex&reIndexFailedMessagesOf=bbdb69c9-082a-44b0-a85a-6e33e74287a5&messagesPerSecond=200&mode=rebuildAll |
| .... |
| |
| The scheduled task will have the following type |
| `error-recovery-indexation` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"error-recovery-indexation" |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"REBUILD_ALL" |
| }, |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12", "23" ], |
| "messageFailures": [{ |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| } |
| .... |
| |
| ===== Create missing parent mailboxes |
| |
| Will schedule a task for creating all the missing parent mailboxes in a hierarchical mailbox tree, which is the result |
| of a partially failed rename operation of a child mailbox. |
| |
| .... |
| curl -XPOST http://ip:port/mailboxes?task=createMissingParents |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The scheduled task will have the following type `createMissingParents` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"createMissingParents" |
| "created": ["1", "2" ], |
| "totalCreated": 2, |
| "failures": [], |
| "totalFailure": 0 |
| } |
| .... |
| |
| === Single mailbox |
| |
| ==== ReIndexing a mailbox mails |
| |
| .... |
| curl -XPOST http://ip:port/mailboxes/{mailboxId}?task=reIndex |
| .... |
| |
| Will schedule a task for reIndexing all the mails in one mailbox. |
| |
| Note that `mailboxId' path parameter needs to be a (implementation |
| dependent) valid mailboxId. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed per |
| second. Default is 50. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter. |
| |
| An admin can also specify the reindexing mode it wants to use when |
| running the task: |
| |
| * `mode` the reindexing mode used. There are 2 modes for the moment: |
| ** `rebuildAll` allows to rebuild all indexes. This is the default mode. |
| ** `fixOutdated` will check for outdated indexed document and reindex |
| only those. |
| |
| This optional parameter must be passed as query parameter. |
| |
| It’s good to note as well that there is a limitation with the |
| `fixOutdated` mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed `expunged` operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed). |
| |
| Example: |
| |
| .... |
| curl -XPOST http://ip:port/mailboxes/{mailboxId}?task=reIndex&messagesPerSecond=200&mode=fixOutdated |
| .... |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The scheduled task will have the following type `mailbox-reindexing` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"mailbox-reindexing", |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"FIX_OUTDATED" |
| }, |
| "mailboxId":"{mailboxId}", |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12"], |
| "messageFailures": [ |
| { |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| } |
| .... |
| |
| Warning: During the re-indexing, the result of search operations might |
| be altered. |
| |
| Warning: Canceling this task should be considered unsafe as it will |
| leave the currently reIndexed mailbox as partially indexed. |
| |
| Warning: While we have been trying to reduce the inconsistency window to |
| a maximum (by keeping track of ongoing events), concurrent changes done |
| during the reIndexing might be ignored. |
| |
| include::{admin-mailboxes-extend}[] |
| |
| == Administrating Messages |
| |
| === ReIndexing a single mail by messageId |
| |
| .... |
| curl -XPOST http://ip:port/messages/{messageId}?task=reIndex |
| .... |
| |
| Will schedule a task for reIndexing a single email in all the mailboxes |
| containing it. |
| |
| Note that `messageId' path parameter needs to be a (implementation |
| dependent) valid messageId. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The scheduled task will have the following type `messageId-reindexing` |
| and the following `additionalInformation`: |
| |
| .... |
| { |
| "messageId":"18" |
| } |
| .... |
| |
| Warning: During the re-indexing, the result of search operations might |
| be altered. |
| |
| === Deleting old messages of all users |
| |
| *Note:* |
| Consider enabling the xref:{xref-base}/configure/vault.adoc[Deleted Messages Vault] |
| if you use this feature. |
| |
| Old messages tend to pile up in user INBOXes. An admin might want to delete |
| these on behalf of the users, e.g. all messages older than 30 days: |
| .... |
| curl -XDELETE http://ip:port/messages?olderThan=30d |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning a task]. |
| |
| The `olderThan` parameter should be expressed in the following format: `Nunit`. |
| `N` should be strictly positive. `unit` could be either in the short form |
| (`d`, `w`, `y` etc.), or in the long form (`days`, `weeks`, `months`, `years`). |
| The default unit is `days`. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The scheduled task will have the type `ExpireMailboxTask` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type": "ExpireMailboxTask" |
| "mailboxesExpired": 5, |
| "mailboxesFailed": 2, |
| "mailboxesProcessed": 10, |
| "messagesDeleted": 23, |
| } |
| .... |
| |
| To delete old mails from a different mailbox than INBOX, e.g. a mailbox |
| named "Archived" : |
| .... |
| curl -XDELETE http://ip:port/messages?mailbox=Archived&olderThan=30d |
| .... |
| |
| Since this is a somewhat expensive operation, the task is throttled to one user |
| per second. You may speed it up via `usersPerSecond=10` for example. But keep |
| in mind that a high rate might overwhelm your database or blob store. |
| |
| The following options are also supported: |
| - `user` query parameter: target a specific user and not all users |
| - `useSavedDate` query parameter: list all the mails of the mailbox and uses saved date (see RFC-8514) instead of internal date. |
| |
| *Scanning search only:* (unsupported for Lucene and OpenSearch search implementations) + |
| Some mail clients can add an `Expires` header (RFC 4021) to their messages. |
| Instead of specifying an absolute age, you may choose to delete only such |
| messages where the expiration date from this header lies in the past: |
| .... |
| curl -XDELETE http://ip:port/messages?byExpiresHeader |
| .... |
| In this case you should also add the xref:{xref-base}/configure/mailets.adoc[mailet] |
| `Expires` to your mailet container, which can sanitize expiration date headers. |
| |
| include::{admin-messages-extend}[] |
| |
| === Running a filtering rule on a specific mailbox for all users |
| |
| .... |
| curl -XPOST http://ip:port/messages?action=triage&mailboxName={mailboxName} \ |
| -d '{ |
| "id": "1", |
| "name": "rule 1", |
| "action": { |
| "moveTo": { |
| "mailboxName": "Trash" |
| } |
| }, |
| "conditionGroup": { |
| "conditionCombiner": "OR", |
| "conditions": [ |
| { |
| "comparator": "contains", |
| "field": "subject", |
| "value": "plop" |
| }, |
| { |
| "comparator": "exactly-equals", |
| "field": "from", |
| "value": "bob@example.com" |
| } |
| ] |
| } |
| }' |
| .... |
| |
| Will schedule a task for each user running a filtering rule passed as query parameter in ``mailboxName`` mailbox. |
| |
| Query parameter `mailboxName` should not be empty, nor contain `% *` characters, nor starting with `#`. |
| If a user does not have a mailbox with that name, it will skip that user. |
| |
| The action of the rule should be `moveTo` with a mailbox name defined. If mailbox ids are defined in `appendIn` action, |
| it will fail, as it makes no sense cluster scoped. |
| |
| Response codes: |
| |
| * 201: Success. Map[Username, TaskId] is returned. |
| * 400: Invalid mailbox name |
| * 400: Invalid JSON payload (including mailbox ids defined in the action) |
| * 400: mailboxName query parameter is missing |
| |
| The response is a map of task id per user: |
| |
| .... |
| [ |
| { |
| "username": "alice@example.org", "taskId": "5641376-02ed-47bd-bcc7-76ff6262d92a" |
| }, |
| { |
| "username": "bob@example.org", "taskId": "5641376-02ed-47bd-bcc7-42cc1313f47b" |
| }, |
| |
| [...] |
| |
| ] |
| .... |
| |
| link:#_running_a_filtering_rule_on_a_mailbox[More details about details returned by running a filtering rule on a mailbox]. |
| |
| == Administrating user mailboxes |
| |
| === Creating a mailbox |
| |
| .... |
| curl -XPUT http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxNameToBeCreated} |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user Resource |
| name `mailboxNameToBeCreated` should not be empty, nor contain % * characters, nor starting with #. |
| |
| Response codes: |
| |
| * 204: The mailbox now exists on the server |
| * 400: Invalid mailbox name |
| * 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. |
| |
| To create nested mailboxes, for instance a work mailbox inside the INBOX |
| mailbox, people should use the . separator. The sample query is: |
| |
| .... |
| curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes/INBOX.work |
| .... |
| |
| === Deleting a mailbox and its children |
| |
| .... |
| curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxNameToBeDeleted} |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user Resource |
| name `mailboxNameToBeDeleted` should not be empty |
| |
| Response codes: |
| |
| * 204: The mailbox now does not exist on the server |
| * 400: Invalid mailbox name |
| * 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. |
| |
| === Testing existence of a mailbox |
| |
| .... |
| curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxNameToBeTested} |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user Resource |
| name `mailboxNameToBeTested` should not be empty |
| |
| Response codes: |
| |
| * 204: The mailbox exists |
| * 400: Invalid mailbox name |
| * 404: The user name does not exist, the mailbox does not exist |
| |
| === Listing user mailboxes |
| |
| .... |
| curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes |
| .... |
| |
| The answer looks like: |
| |
| .... |
| [{"mailboxName":"INBOX"},{"mailboxName":"outbox"}] |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| Response codes: |
| |
| * 200: The mailboxes list was successfully retrieved |
| * 404: The user name does not exist, the mailbox does not exist. Note that this check can be bypassed by specifying the `force` query parameter. |
| |
| |
| === Deleting user mailboxes |
| |
| .... |
| curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| Response codes: |
| |
| * 204: The user do not have mailboxes anymore |
| * 404: The user name does not exist. Note that this check can be bypassed by specifying the `force` query parameter. |
| |
| === Exporting user mailboxes |
| |
| .... |
| curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?action=export |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned |
| * 404: The user name does not exist |
| |
| The scheduled task will have the following type `MailboxesExportTask` |
| and the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"MailboxesExportTask", |
| "timestamp":"2007-12-03T10:15:30Z", |
| "username": "user", |
| "stage": "STARTING" |
| } |
| .... |
| |
| === ReIndexing a user mails |
| |
| .... |
| curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?task=reIndex |
| .... |
| |
| Will schedule a task for reIndexing all the mails in ``user@domain.com'' |
| mailboxes (encoded above). |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed per |
| second. Default is 50. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter. |
| |
| An admin can also specify the reindexing mode it wants to use when |
| running the task: |
| |
| * `mode` the reindexing mode used. There are 2 modes for the moment: |
| ** `rebuildAll` allows to rebuild all indexes. This is the default mode. |
| ** `fixOutdated` will check for outdated indexed document and reindex |
| only those. |
| |
| This optional parameter must be passed as query parameter. |
| |
| It’s good to note as well that there is a limitation with the |
| `fixOutdated` mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed `expunged` operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed). |
| |
| Example: |
| |
| .... |
| curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?task=reIndex&messagesPerSecond=200&mode=fixOutdated |
| .... |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| |
| The scheduled task will have the following type `user-reindexing` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"user-reindexing", |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"FIX_OUTDATED" |
| }, |
| "user":"user@domain.com", |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12", "23" ], |
| "messageFailures": [ |
| { |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| } |
| .... |
| |
| Warning: During the re-indexing, the result of search operations might |
| be altered. |
| |
| Warning: Canceling this task should be considered unsafe as it will |
| leave the currently reIndexed mailbox as partially indexed. |
| |
| Warning: While we have been trying to reduce the inconsistency window to |
| a maximum (by keeping track of ongoing events), concurrent changes done |
| during the reIndexing might be ignored. |
| |
| === Counting emails |
| |
| .... |
| curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/messageCount |
| .... |
| |
| Will return the total count of messages within the mailbox of that user. |
| |
| Resource name `usernameToBeUsed` should be an existing user. |
| |
| Resource name `mailboxName` should not be empty, nor contain `% *` characters, nor starting with `#`. |
| |
| Response codes: |
| |
| * 200: The number of emails in a given mailbox |
| * 400: Invalid mailbox name |
| * 404: Invalid get on user mailboxes. The `usernameToBeUsed` or `mailboxName` does not exit' |
| |
| === Counting unseen emails |
| |
| .... |
| curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/unseenMessageCount |
| .... |
| |
| Will return the total count of unseen messages within the mailbox of that user. |
| |
| Resource name `usernameToBeUsed` should be an existing user. |
| |
| Resource name `mailboxName` should not be empty, nor contain `% *` characters, nor starting with `#`. |
| |
| Response codes: |
| |
| * 200: The number of unseen emails in a given mailbox |
| * 400: Invalid mailbox name |
| * 404: Invalid get on user mailboxes. The `usernameToBeUsed` or `mailboxName` does not exit' |
| |
| === Clearing mailbox content |
| |
| .... |
| curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/messages |
| .... |
| |
| Will schedule a task for clearing all the mails in ``mailboxName`` mailbox of ``usernameToBeUsed``. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Resource name `usernameToBeUsed` should be an existing user. |
| |
| Resource name `mailboxName` should not be empty, nor contain `% *` characters, nor starting with `#`. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Invalid mailbox name |
| * 404: Invalid get on user mailboxes. The `username` or `mailboxName` does not exit |
| |
| The scheduled task will have the following type `ClearMailboxContentTask` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "mailboxPath": "#private:bob@domain.tld:mbx1", |
| "messagesFailCount": 9, |
| "messagesSuccessCount": 10, |
| "timestamp": "2007-12-03T10:15:30Z", |
| "type": "ClearMailboxContentTask", |
| "username": "bob@domain.tld" |
| } |
| .... |
| |
| === Running a filtering rule on a mailbox |
| |
| .... |
| curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/messages?action=triage \ |
| -d '{ |
| "id": "1", |
| "name": "rule 1", |
| "action": { |
| "appendIn": { |
| "mailboxIds": ["23"] |
| } |
| }, |
| "conditionGroup": { |
| "conditionCombiner": "OR", |
| "conditions": [ |
| { |
| "comparator": "contains", |
| "field": "subject", |
| "value": "plop" |
| }, |
| { |
| "comparator": "exactly-equals", |
| "field": "from", |
| "value": "bob@example.com" |
| } |
| ] |
| } |
| }' |
| .... |
| |
| Will schedule a task for running a filtering rule passed as payload in ``mailboxName`` mailbox of ``usernameToBeUsed``. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Resource name `usernameToBeUsed` should be an existing user. |
| |
| Resource name `mailboxName` should not be empty, nor contain `% *` characters, nor starting with `#`. |
| |
| The rule json payload has some extra conditions available compared to the JMAP filtering mailet as some operations would make sense: |
| |
| - Flags: |
| * field: flag |
| * comparators: isSet, isUnset |
| * value: system flag ("$seen", "$flagged", etc) or a custom user flag. |
| |
| - Dates: |
| * fields: sentDate, savedDate, internalDate |
| * comparators: isOlderThan, isNewerThan |
| * values: durations ("2d", "6h", ...) |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Invalid mailbox name |
| * 400: Invalid JSON payload |
| * 404: Invalid get on user mailboxes. The `username` or `mailboxName` does not exit |
| |
| The scheduled task will have the following type `RunRulesOnMailboxTask` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "mailboxPath": "#private:bob@domain.tld:mbx1", |
| "processedMessagesCount": 15, |
| "rulesOnMessagesApplySuccessfully": 9, |
| "rulesOnMessagesApplyFailed": 3, |
| "maximumAppliedActionExceeded": false, |
| "timestamp": "2024-12-03T10:15:30Z", |
| "type": "RunRulesOnMailboxTask", |
| "username": "bob@domain.tld" |
| } |
| .... |
| |
| Note: you can configure the maximum number of actions applied per mailbox by setting the JVM property `james.rules.triage.max.actions.per.mailbox`. The default value is 25000. |
| This limit may help avoid the tombstone threshold issue on Cassandra backends when too many messages are moved or deleted at once. |
| |
| === Subscribing a user to all of its mailboxes |
| |
| .... |
| curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?task=subscribeAll |
| .... |
| |
| Will schedule a task for subscribing a user to all of its mailboxes. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Most users are unaware of what an IMAP subscription is, nor how they can manage it. If the subscription list gets out |
| of sync with the mailbox list, it could result in downgraded user experience (see MAILBOX-405). This task allow |
| to reset the subscription list to the mailbox list on a per user basis thus working around the aforementioned issues. |
| |
| Response codes: |
| |
| - 201: Success. Corresponding task id is returned. |
| - 404: No such user |
| |
| The scheduled task will have the following type `SubscribeAllTask` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"SubscribeAllTask", |
| "username":"user@domain.com", |
| "subscribedCount":18, |
| "unsubscribedCount": 3 |
| } |
| .... |
| |
| === Recomputing User JMAP fast message view projection |
| |
| This action is only available for backends supporting JMAP protocol. |
| |
| Message fast view projection stores message properties expected to be |
| fast to fetch but are actually expensive to compute, in order for |
| GetMessages operation to be fast to execute for these properties. |
| |
| These projection items are asynchronously computed on mailbox events. |
| |
| You can force the full projection recomputation by calling the following |
| endpoint: |
| |
| .... |
| curl -XPOST /users/{usernameToBeUsed}/mailboxes?task=recomputeFastViewProjectionItems |
| .... |
| |
| Will schedule a task for recomputing the fast message view projection |
| for all mailboxes of `usernameToBeUsed`. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `messagesPerSecond` rate at which messages should be processed, per |
| second. Defaults to 10. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters. |
| |
| Example: |
| |
| .... |
| curl -XPOST /mailboxes?task=recomputeFastViewProjectionItems&messagesPerSecond=20 |
| .... |
| |
| The scheduled task will have the following type |
| `RecomputeUserFastViewProjectionItemsTask` and the following |
| `additionalInformation`: |
| |
| .... |
| { |
| "type":"RecomputeUserFastViewProjectionItemsTask", |
| "username": "{usernameToBeUsed}", |
| "processedMessageCount": 3, |
| "failedMessageCount": 1, |
| "runningOptions": { |
| "messagesPerSecond":20 |
| } |
| } |
| .... |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Error in the request. Details can be found in the reported error. |
| * 404: User not found. |
| |
| == Administrating quotas |
| |
| === Administrating quotas by users |
| |
| ==== Getting the quota for a user |
| |
| .... |
| curl -XGET http://ip:port/quota/users/{usernameToBeUsed} |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| The answer is the details of the quota of that user. |
| |
| .... |
| { |
| "global": { |
| "count":252, |
| "size":242 |
| }, |
| "domain": { |
| "count":152, |
| "size":142 |
| }, |
| "user": { |
| "count":52, |
| "size":42 |
| }, |
| "computed": { |
| "count":52, |
| "size":42 |
| }, |
| "occupation": { |
| "size":13, |
| "count":21, |
| "ratio": { |
| "size":0.25, |
| "count":0.5, |
| "max":0.5 |
| } |
| } |
| } |
| .... |
| |
| * The `global` entry represent the quota limit allowed on this James |
| server. |
| * The `domain` entry represent the quota limit allowed for the user of |
| that domain. |
| * The `user` entry represent the quota limit allowed for this specific |
| user. |
| * The `computed` entry represent the quota limit applied for this user, |
| resolved from the upper values. |
| * The `occupation` entry represent the occupation of the quota for this |
| user. This includes used count and size as well as occupation ratio |
| (used / limit). |
| |
| Note that `quota` object can contain a fixed value, an empty value |
| (null) or an unlimited value (-1): |
| |
| .... |
| {"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1} |
| .... |
| |
| Response codes: |
| |
| * 200: The user’s quota was successfully retrieved |
| * 404: The user does not exist |
| |
| ==== Updating the quota for a user |
| |
| .... |
| curl -XPUT http://ip:port/quota/users/{usernameToBeUsed} |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| The body can contain a fixed value, an empty value (null) or an |
| unlimited value (-1): |
| |
| .... |
| {"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1} |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| * 404: The user does not exist |
| |
| ==== Getting the quota count for a user |
| |
| .... |
| curl -XGET http://ip:port/quota/users/{usernameToBeUsed}/count |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| The answer looks like: |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 200: The user’s quota was successfully retrieved |
| * 204: No quota count limit is defined at the user level for this user |
| * 404: The user does not exist |
| |
| ==== Updating the quota count for a user |
| |
| .... |
| curl -XPUT http://ip:port/quota/users/{usernameToBeUsed}/count |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| The body can contain a fixed value or an unlimited value (-1): |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| * 404: The user does not exist |
| |
| ==== Deleting the quota count for a user |
| |
| .... |
| curl -XDELETE http://ip:port/quota/users/{usernameToBeUsed}/count |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| Response codes: |
| |
| * 204: The quota has been updated to unlimited value. |
| * 404: The user does not exist |
| |
| ==== Getting the quota size for a user |
| |
| .... |
| curl -XGET http://ip:port/quota/users/{usernameToBeUsed}/size |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| The answer looks like: |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 200: The user’s quota was successfully retrieved |
| * 204: No quota size limit is defined at the user level for this user |
| * 404: The user does not exist |
| |
| ==== Updating the quota size for a user |
| |
| .... |
| curl -XPUT http://ip:port/quota/users/{usernameToBeUsed}/size |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| The body can contain a fixed value or an unlimited value (-1): |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| * 404: The user does not exist |
| |
| ==== Deleting the quota size for a user |
| |
| .... |
| curl -XDELETE http://ip:port/quota/users/{usernameToBeUsed}/size |
| .... |
| |
| Resource name `usernameToBeUsed` should be an existing user |
| |
| Response codes: |
| |
| * 204: The quota has been updated to unlimited value. |
| * 404: The user does not exist |
| |
| ==== Searching user by quota ratio |
| |
| .... |
| curl -XGET 'http://ip:port/quota/users?minOccupationRatio=0.8&maxOccupationRatio=0.99&limit=100&offset=200&domain=domain.com' |
| .... |
| |
| Will return: |
| |
| .... |
| [ |
| { |
| "username":"user@domain.com", |
| "detail": { |
| "global": { |
| "count":252, |
| "size":242 |
| }, |
| "domain": { |
| "count":152, |
| "size":142 |
| }, |
| "user": { |
| "count":52, |
| "size":42 |
| }, |
| "computed": { |
| "count":52, |
| "size":42 |
| }, |
| "occupation": { |
| "size":48, |
| "count":21, |
| "ratio": { |
| "size":0.9230, |
| "count":0.5, |
| "max":0.9230 |
| } |
| } |
| } |
| }, |
| ... |
| ] |
| .... |
| |
| Where: |
| |
| * *minOccupationRatio* is a query parameter determining the minimum |
| occupation ratio of users to be returned. |
| * *maxOccupationRatio* is a query parameter determining the maximum |
| occupation ratio of users to be returned. |
| * *domain* is a query parameter determining the domain of users to be |
| returned. |
| * *limit* is a query parameter determining the maximum number of users |
| to be returned. |
| * *offset* is a query parameter determining the number of users to skip. |
| |
| Please note that users are alphabetically ordered on username. |
| |
| The response is a list of usernames, with attached quota details as |
| defined link:#_getting_the_quota_for_a_user[here]. |
| |
| Response codes: |
| |
| * 200: List of users had successfully been returned. |
| * 400: Validation issues with parameters |
| |
| ==== Recomputing current quotas for users |
| |
| .... |
| curl -XPOST /quota/users?task=RecomputeCurrentQuotas |
| .... |
| |
| Will recompute current quotas (count and size) for all users stored in |
| James. |
| |
| James maintains per quota a projection for current quota count and size. |
| As with any projection, it can go out of sync, leading to inconsistent |
| results being returned to the client. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| An admin can specify the concurrency that should be used when running |
| the task: |
| |
| * `usersPerSecond` rate at which users quotas should be reprocessed, per |
| second. Defaults to 1. |
| |
| This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters. |
| |
| An admin can select which quota component he wants to recompute: |
| |
| * `quotaComponent` component whose quota need to be reprocessed. It could be one of values: MAILBOX, SIEVE, JMAP_UPLOADS. |
| |
| The admin could select several quota components. If he does not select, quotas of all components would be recomputed. |
| |
| Example: |
| |
| .... |
| curl -XPOST /quota/users?task=RecomputeCurrentQuotas&usersPerSecond=20"aComponent=MAILBOX"aComponent=JMAP_UPLOADS |
| .... |
| |
| The scheduled task will have the following type |
| `recompute-current-quotas` and the following `additionalInformation`: |
| |
| .... |
| { |
| "type":"recompute-current-quotas", |
| "recomputeSingleQuotaComponentResults": [ |
| { |
| "quotaComponent": "MAILBOX", |
| "processedIdentifierCount": 3, |
| "failedIdentifiers": ["#private&bob@localhost"] |
| }, |
| { |
| "quotaComponent": "JMAP_UPLOADS", |
| "processedIdentifierCount": 3, |
| "failedIdentifiers": ["bob@localhost"] |
| } |
| ], |
| "runningOptions": { |
| "usersPerSecond":20 |
| } |
| } |
| .... |
| |
| *WARNING*: this task do not take into account concurrent modifications |
| upon a single current quota re-computation. Rerunning the task will |
| _eventually_ provide the consistent result. |
| |
| === Administrating quotas by domains |
| |
| ==== Getting the quota for a domain |
| |
| .... |
| curl -XGET http://ip:port/quota/domains/{domainToBeUsed} |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. For |
| example: |
| |
| .... |
| curl -XGET http://ip:port/quota/domains/james.org |
| .... |
| |
| The answer will detail the default quota applied to users belonging to |
| that domain: |
| |
| .... |
| { |
| "global": { |
| "count":252, |
| "size":null |
| }, |
| "domain": { |
| "count":null, |
| "size":142 |
| }, |
| "computed": { |
| "count":252, |
| "size":142 |
| } |
| } |
| .... |
| |
| * The `global` entry represents the quota limit defined on this James |
| server by default. |
| * The `domain` entry represents the quota limit allowed for the user of |
| that domain by default. |
| * The `computed` entry represents the quota limit applied for the users |
| of that domain, by default, resolved from the upper values. |
| |
| Note that `quota` object can contain a fixed value, an empty value |
| (null) or an unlimited value (-1): |
| |
| .... |
| {"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1} |
| .... |
| |
| Response codes: |
| |
| * 200: The domain’s quota was successfully retrieved |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| deactivated. |
| |
| ==== Updating the quota for a domain |
| |
| .... |
| curl -XPUT http://ip:port/quota/domains/{domainToBeUsed} |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| The body can contain a fixed value, an empty value (null) or an |
| unlimited value (-1): |
| |
| .... |
| {"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1} |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| deactivated. |
| |
| ==== Getting the quota count for a domain |
| |
| .... |
| curl -XGET http://ip:port/quota/domains/{domainToBeUsed}/count |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| The answer looks like: |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 200: The domain’s quota was successfully retrieved |
| * 204: No quota count limit is defined at the domain level for this |
| domain |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| desactivated. |
| |
| ==== Updating the quota count for a domain |
| |
| .... |
| curl -XPUT http://ip:port/quota/domains/{domainToBeUsed}/count |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| The body can contain a fixed value or an unlimited value (-1): |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| desactivated. |
| |
| ==== Deleting the quota count for a domain |
| |
| .... |
| curl -XDELETE http://ip:port/quota/domains/{domainToBeUsed}/count |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| Response codes: |
| |
| * 204: The quota has been updated to unlimited value. |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| deactivated. |
| |
| ==== Getting the quota size for a domain |
| |
| .... |
| curl -XGET http://ip:port/quota/domains/{domainToBeUsed}/size |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| The answer looks like: |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 200: The domain’s quota was successfully retrieved |
| * 204: No quota size limit is defined at the domain level for this |
| domain |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| deactivated. |
| |
| ==== Updating the quota size for a domain |
| |
| .... |
| curl -XPUT http://ip:port/quota/domains/{domainToBeUsed}/size |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| The body can contain a fixed value or an unlimited value (-1): |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| * 404: The domain does not exist |
| * 405: Domain Quota configuration not supported when virtual hosting is |
| deactivated. |
| |
| ==== Deleting the quota size for a domain |
| |
| .... |
| curl -XDELETE http://ip:port/quota/domains/{domainToBeUsed}/size |
| .... |
| |
| Resource name `domainToBeUsed` should be an existing domain. |
| |
| Response codes: |
| |
| * 204: The quota has been updated to unlimited value. |
| * 404: The domain does not exist |
| |
| === Administrating global quotas |
| |
| ==== Getting the global quota |
| |
| .... |
| curl -XGET http://ip:port/quota |
| .... |
| |
| The answer is the details of the global quota. |
| |
| .... |
| { |
| "count":252, |
| "size":242 |
| } |
| .... |
| |
| Note that `quota` object can contain a fixed value, an empty value |
| (null) or an unlimited value (-1): |
| |
| .... |
| {"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1} |
| .... |
| |
| Response codes: |
| |
| * 200: The quota was successfully retrieved |
| |
| ==== Updating global quota |
| |
| .... |
| curl -XPUT http://ip:port/quota |
| .... |
| |
| The body can contain a fixed value, an empty value (null) or an |
| unlimited value (-1): |
| |
| .... |
| {"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1} |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| |
| ==== Getting the global quota count |
| |
| .... |
| curl -XGET http://ip:port/quota/count |
| .... |
| |
| Resource name usernameToBeUsed should be an existing user |
| |
| The answer looks like: |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 200: The quota was successfully retrieved |
| * 204: No quota count limit is defined at the global level |
| |
| ==== Updating the global quota count |
| |
| .... |
| curl -XPUT http://ip:port/quota/count |
| .... |
| |
| The body can contain a fixed value or an unlimited value (-1): |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| |
| ==== Deleting the global quota count |
| |
| .... |
| curl -XDELETE http://ip:port/quota/count |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated to unlimited value. |
| |
| ==== Getting the global quota size |
| |
| .... |
| curl -XGET http://ip:port/quota/size |
| .... |
| |
| The answer looks like: |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 200: The quota was successfully retrieved |
| * 204: No quota size limit is defined at the global level |
| |
| ==== Updating the global quota size |
| |
| .... |
| curl -XPUT http://ip:port/quota/size |
| .... |
| |
| The body can contain a fixed value or an unlimited value (-1): |
| |
| .... |
| 52 |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated |
| * 400: The body is not a positive integer neither an unlimited value |
| (-1). |
| |
| ==== Deleting the global quota size |
| |
| .... |
| curl -XDELETE http://ip:port/quota/size |
| .... |
| |
| Response codes: |
| |
| * 204: The quota has been updated to unlimited value. |
| |
| === Administrating DropLists |
| |
| The DropList, also known as the mail blacklist, is a collection of |
| domains and email addresses that are denied from sending emails within the system. |
| |
| Owner scopes: |
| |
| - *global*: contains entries that are blocked across all domains and addresses within the system. |
| Entries in the global owner scope apply universally and affect all users and domains. |
| - *domain*: each domain can have its own droplist, which contains entries specific to that domain. |
| - *user*: allow to customize personalized droplist of blocked domains and email addresses. |
| |
| The `deniedEntityType` query parameter is optional and can take the values `domain` or `address`. |
| |
| ==== Getting the DropList |
| |
| ===== Global DropList |
| |
| .... |
| curl -XGET http://ip:port/droplist/global?deniedEntityType=null|domain|address |
| .... |
| |
| ===== Domain DropList |
| |
| .... |
| curl -XGET http://ip:port/droplist/domain/target.com?deniedEntityType=null|domain|address |
| .... |
| |
| ===== User DropList |
| |
| .... |
| curl -XGET http://ip:port/droplist/user/tagret@target.com?deniedEntityType=null|domain|address |
| .... |
| |
| The answer looks like: |
| |
| .... |
| [ "evil.com", "devil.com", "bad_guy@crime.com", "hacker@murder.org" ] |
| .... |
| |
| Response codes: |
| |
| * 200: The drop list was successfully retrieved |
| * 400: Invalid `owner scope` or `deniedEntityType` |
| |
| ==== Testing a denied entity existence |
| |
| ===== Global DropList |
| |
| .... |
| curl -XHEAD http://ip:port/droplist/global/attacker@evil.com |
| .... |
| |
| .... |
| curl -XHEAD http://ip:port/droplist/global/evil.com |
| .... |
| |
| ===== Domain DropList |
| |
| .... |
| curl -XHEAD http://ip:port/droplist/domain/target.com/attacker@evil.com |
| .... |
| |
| .... |
| curl -XHEAD http://ip:port/droplist/domain/target.com/evil.com |
| .... |
| |
| ===== User DropList |
| |
| .... |
| curl -XHEAD http://ip:port/droplist/user/target@target.com/attacker@evil.com |
| .... |
| |
| .... |
| curl -XHEAD http://ip:port/droplist/user/target@target.com/evil.com |
| .... |
| |
| Response codes: |
| |
| * 200: The denied entity exists |
| * 404: The denied entity does not exist |
| |
| ==== Add Entry to the DropList |
| |
| The denied entity must be a valid email address or link:#_create_a_domain[domain]. |
| |
| ===== Global DropList |
| |
| .... |
| curl -XPUT http://ip:port/droplist/global/attacker@evil.com |
| .... |
| |
| .... |
| curl -XPUT http://ip:port/droplist/global/evil.com |
| .... |
| |
| ===== Domain DropList |
| |
| .... |
| curl -XPUT http://ip:port/droplist/domain/target.com/attacker@evil.com |
| .... |
| |
| .... |
| curl -XPUT http://ip:port/droplist/domain/target.com/evil.com |
| .... |
| |
| ===== User DropList |
| |
| .... |
| curl -XPUT http://ip:port/droplist/user/target@target.com/attacker@evil.com |
| .... |
| |
| .... |
| curl -XPUT http://ip:port/droplist/user/target@target.com/evil.com |
| .... |
| |
| Response codes: |
| |
| * 204: The denied entity was successfully added |
| * 400: The denied entity is invalid |
| |
| ==== Remove Entry from the DropList |
| |
| ===== Global DropList |
| |
| .... |
| curl -XDELETE http://ip:port/droplist/global/attacker@evil.com |
| .... |
| |
| .... |
| curl -XDELETE http://ip:port/droplist/global/evil.com |
| .... |
| |
| ===== Domain DropList |
| |
| .... |
| curl -XDELETE http://ip:port/droplist/domain/target.com/attacker@evil.com |
| .... |
| |
| .... |
| curl -XDELETE http://ip:port/droplist/domain/target.com/evil.com |
| .... |
| |
| ===== User DropList |
| |
| .... |
| curl -XDELETE http://ip:port/droplist/user/target@target.com/attacker@evil.com |
| .... |
| |
| .... |
| curl -XDELETE http://ip:port/droplist/user/target@target.com/evil.com |
| .... |
| |
| Response codes: |
| |
| * 204: Entry deleted successfully. |
| |
| === Administrating Sieve quotas |
| |
| Some limitations on space Users Sieve script can occupy can be |
| configured by default, and overridden by user. |
| |
| ==== Retrieving global sieve quota |
| |
| This endpoints allows to retrieve the global Sieve quota, which will be |
| users default: |
| |
| .... |
| curl -XGET http://ip:port/sieve/quota/default |
| .... |
| |
| Will return the bytes count allowed by user per default on this server. |
| |
| .... |
| 102400 |
| .... |
| |
| Response codes: |
| |
| * 200: Request is a success and the value is returned |
| * 204: No default quota is being configured |
| |
| ==== Updating global sieve quota |
| |
| This endpoints allows to update the global Sieve quota, which will be |
| users default: |
| |
| .... |
| curl -XPUT http://ip:port/sieve/quota/default |
| .... |
| |
| With the body being the bytes count allowed by user per default on this |
| server. |
| |
| .... |
| 102400 |
| .... |
| |
| Response codes: |
| |
| * 204: Operation succeeded |
| * 400: Invalid payload |
| |
| ==== Removing global sieve quota |
| |
| This endpoints allows to remove the global Sieve quota. There will no |
| more be users default: |
| |
| .... |
| curl -XDELETE http://ip:port/sieve/quota/default |
| .... |
| |
| Response codes: |
| |
| * 204: Operation succeeded |
| |
| ==== Retrieving user sieve quota |
| |
| This endpoints allows to retrieve the Sieve quota of a user, which will |
| be this users quota: |
| |
| .... |
| curl -XGET http://ip:port/sieve/quota/users/user@domain.com |
| .... |
| |
| Will return the bytes count allowed for this user. |
| |
| .... |
| 102400 |
| .... |
| |
| Response codes: |
| |
| * 200: Request is a success and the value is returned |
| * 204: No quota is being configured for this user |
| |
| ==== Updating user sieve quota |
| |
| This endpoints allows to update the Sieve quota of a user, which will be |
| users default: |
| |
| .... |
| curl -XPUT http://ip:port/sieve/quota/users/user@domain.com |
| .... |
| |
| With the body being the bytes count allowed for this user on this |
| server. |
| |
| .... |
| 102400 |
| .... |
| |
| Response codes: |
| |
| * 204: Operation succeeded |
| * 400: Invalid payload |
| |
| ==== Removing user sieve quota |
| |
| This endpoints allows to remove the Sieve quota of a user. There will no |
| more quota for this user: |
| |
| .... |
| curl -XDELETE http://ip:port/sieve/quota/users/user@domain.com |
| .... |
| |
| Response codes: |
| |
| * 204: Operation succeeded |
| |
| == Administrating Jmap Uploads |
| |
| === Cleaning upload repository |
| |
| .... |
| curl -XDELETE http://ip:port/jmap/uploads?scope=expired |
| .... |
| |
| Will schedule a task for clearing expired upload entries. |
| |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| |
| Query parameter `scope` is required and have the value `expired`. |
| |
| Response codes: |
| |
| * 201: Success. Corresponding task id is returned. |
| * 400: Scope invalid |
| |
| The scheduled task will have the following type `UploadRepositoryCleanupTask` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "scope": "expired", |
| "timestamp": "2007-12-03T10:15:30Z", |
| "type": "UploadRepositoryCleanupTask" |
| } |
| .... |
| |
| == Running blob garbage collection |
| |
| When deduplication is enabled one needs to explicitly run a garbage collection in order to delete no longer referenced |
| blobs. |
| |
| To do so: |
| |
| .... |
| curl -XDELETE http://ip:port/blobs?scope=unreferenced |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning a task]. |
| |
| Additional parameters include Bloom filter tuning parameters: |
| |
| - *associatedProbability*: Allow to define the targeted false positive rate. Note that subsequent runs do not have the |
| same false-positives. Defaults to `0.01`. |
| - *expectedBlobCount*: Expected count of blobs used to size the bloom filters. Defaults to `1.000.000`. |
| |
| These settings directly impacts the memory footprint of the bloom filter. link:https://hur.st/bloomfilter/[Simulators] can |
| help understand those parameters. |
| |
| The created task has the following additional information: |
| |
| .... |
| { |
| "referenceSourceCount": 3456, |
| "blobCount": 5678, |
| "gcedBlobCount": 1234, |
| "bloomFilterExpectedBlobCount": 10000, |
| "bloomFilterAssociatedProbability": 0.01 |
| } |
| .... |
| |
| Where: |
| |
| - *bloomFilterExpectedBlobCount* correspond to the supplied *expectedBlobCount* query parameter. |
| - *bloomFilterAssociatedProbability* correspond to the supplied *associatedProbability* query parameter. |
| - *referenceSourceCount* is the count of distinct blob references encountered while populating the bloom filter. |
| - *blobCount* is the count of blobs tried against the bloom filter. This value can be used to better size the bloom |
| filter in later runs. |
| - *gcedBlobCount* is the count of blobs that were garbage collected. |
| |
| == Administrating Recipient rewriting |
| |
| === Address group |
| |
| You can use *webadmin* to define address groups. |
| |
| When a specific email is sent to the group mail address, every group |
| member will receive it. |
| |
| Note that the group mail address is virtual: it does not correspond to |
| an existing user. |
| |
| This feature uses xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table] |
| and requires the |
| https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java[RecipientRewriteTable |
| mailet] to be configured. |
| |
| Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected. |
| |
| ==== Listing groups |
| |
| .... |
| curl -XGET http://ip:port/address/groups |
| .... |
| |
| Will return the groups as a list of JSON Strings representing mail |
| addresses. For instance: |
| |
| .... |
| ["group1@domain.com", "group2@domain.com"] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| |
| ==== Deleting all groups |
| |
| |
| .... |
| curl -XDELETE http://ip:port/address/groups |
| .... |
| |
| Will delete all groups. |
| |
| Response codes: |
| |
| * 204: Success |
| |
| ==== Listing members of a group |
| |
| .... |
| curl -XGET http://ip:port/address/groups/group@domain.com |
| .... |
| |
| Will return the group members as a list of JSON Strings representing |
| mail addresses. For instance: |
| |
| .... |
| ["member1@domain.com", "member2@domain.com"] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| * 400: Group structure is not valid |
| * 404: The group does not exist |
| |
| ==== Adding a group member |
| |
| .... |
| curl -XPUT http://ip:port/address/groups/group@domain.com/member@domain.com |
| .... |
| |
| Will add member@domain.com to group@domain.com, creating the group if |
| needed |
| |
| Response codes: |
| |
| * 204: Success |
| * 400: Group structure or member is not valid |
| * 400: Domain in the source is not managed by the DomainList |
| * 409: Requested group address is already used for another purpose |
| * 409: The addition of the group member would lead to a loop and thus cannot be performed |
| |
| ==== Removing a group member |
| |
| .... |
| curl -XDELETE http://ip:port/address/groups/group@domain.com/member@domain.com |
| .... |
| |
| Will remove member@domain.com from group@domain.com, removing the group |
| if group is empty after deletion |
| |
| Response codes: |
| |
| * 204: Success |
| * 400: Group structure or member is not valid |
| |
| === Address forwards |
| |
| You can use *webadmin* to define address forwards. |
| |
| When a specific email is sent to the base mail address, every forward |
| destination addresses will receive it. |
| |
| Please note that the base address can be optionaly part of the forward |
| destination. In that case, the base recipient also receive a copy of the |
| mail. Otherwise he is omitted. |
| |
| Forwards can be defined for existing users. It then defers from |
| ``groups''. |
| |
| This feature uses xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table] |
| and requires the |
| https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java[RecipientRewriteTable |
| mailet] to be configured. |
| |
| Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected. |
| |
| ==== Listing Forwards |
| |
| .... |
| curl -XGET http://ip:port/address/forwards |
| .... |
| |
| Will return the users having forwards configured as a list of JSON |
| Strings representing mail addresses. For instance: |
| |
| .... |
| ["user1@domain.com", "user2@domain.com"] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| |
| ==== Listing destinations in a forward |
| |
| .... |
| curl -XGET http://ip:port/address/forwards/user@domain.com |
| .... |
| |
| Will return the destination addresses of this forward as a list of JSON |
| Strings representing mail addresses. For instance: |
| |
| .... |
| [ |
| {"mailAddress":"destination1@domain.com"}, |
| {"mailAddress":"destination2@domain.com"} |
| ] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| * 400: Forward structure is not valid |
| * 404: The given user don’t have forwards or does not exist |
| |
| ==== Adding a new destination to a forward |
| |
| .... |
| curl -XPUT http://ip:port/address/forwards/user@domain.com/targets/destination@domain.com |
| .... |
| |
| Will add destination@domain.com to user@domain.com, creating the forward |
| if needed |
| |
| Response codes: |
| |
| * 204: Success |
| * 400: Forward structure or member is not valid |
| * 400: Domain in the source is not managed by the DomainList |
| * 404: Requested forward address does not match an existing user |
| * 409: The creation of the forward would lead to a loop and thus cannot be performed |
| |
| ==== Removing a destination of a forward |
| |
| .... |
| curl -XDELETE http://ip:port/address/forwards/user@domain.com/targets/destination@domain.com |
| .... |
| |
| Will remove destination@domain.com from user@domain.com, removing the |
| forward if forward is empty after deletion |
| |
| Response codes: |
| |
| * 204: Success |
| * 400: Forward structure or member is not valid |
| |
| === Address aliases |
| |
| You can use *webadmin* to define aliases for an user. |
| |
| When a specific email is sent to the alias address, the destination |
| address of the alias will receive it. |
| |
| Aliases can be defined for existing users. |
| |
| This feature uses xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table] |
| and requires the |
| https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java[RecipientRewriteTable |
| mailet] to be configured. |
| |
| Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected. |
| |
| ==== Listing users with aliases |
| |
| .... |
| curl -XGET http://ip:port/address/aliases |
| .... |
| |
| Will return the users having aliases configured as a list of JSON |
| Strings representing mail addresses. For instance: |
| |
| .... |
| ["user1@domain.com", "user2@domain.com"] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| |
| ==== Listing alias sources of an user |
| |
| .... |
| curl -XGET http://ip:port/address/aliases/user@domain.com |
| .... |
| |
| Will return the aliases of this user as a list of JSON Strings |
| representing mail addresses. For instance: |
| |
| .... |
| [ |
| {"source":"alias1@domain.com"}, |
| {"source":"alias2@domain.com"} |
| ] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| * 400: Alias structure is not valid |
| |
| ==== Adding a new alias to an user |
| |
| .... |
| curl -XPUT http://ip:port/address/aliases/user@domain.com/sources/alias@domain.com |
| .... |
| |
| Will add alias@domain.com to user@domain.com, creating the alias if |
| needed |
| |
| Response codes: |
| |
| * 204: OK |
| * 400: Alias structure or member is not valid |
| * 400: Source and destination can’t be the same! |
| * 400: Domain in the destination or source is not managed by the |
| DomainList |
| * 409: The alias source exists as an user already |
| * 409: The addition of the alias would lead to a loop and thus cannot be performed |
| |
| ==== Removing an alias of an user |
| |
| .... |
| curl -XDELETE http://ip:port/address/aliases/user@domain.com/sources/alias@domain.com |
| .... |
| |
| Will remove alias@domain.com from user@domain.com, removing the alias if |
| needed |
| |
| Response codes: |
| |
| * 204: OK |
| * 400: Alias structure or member is not valid |
| |
| === Domain mappings |
| |
| You can use *webadmin* to define domain mappings. |
| |
| Given a configured source (from) domain and a destination (to) domain, |
| when an email is sent to an address belonging to the source domain, then |
| the domain part of this address is overwritten, the destination domain |
| is then used. A source (from) domain can have many destination (to) |
| domains. |
| |
| For example: with a source domain `james.apache.org` maps to two |
| destination domains `james.org` and `apache-james.org`, when a mail is |
| sent to `admin@james.apache.org`, then it will be routed to |
| `admin@james.org` and `admin@apache-james.org` |
| |
| This feature uses xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table] |
| and requires the |
| https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java[RecipientRewriteTable |
| mailet] to be configured. |
| |
| Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected. |
| |
| ==== Listing all domain mappings |
| |
| .... |
| curl -XGET http://ip:port/domainMappings |
| .... |
| |
| Will return all configured domain mappings |
| |
| .... |
| { |
| "firstSource.org" : ["firstDestination.com", "secondDestination.net"], |
| "secondSource.com" : ["thirdDestination.com", "fourthDestination.net"], |
| } |
| .... |
| |
| Response codes: |
| |
| * 200: OK |
| |
| ==== Listing all destination domains for a source domain |
| |
| .... |
| curl -XGET http://ip:port/domainMappings/sourceDomain.tld |
| .... |
| |
| With `sourceDomain.tld` as the value passed to `fromDomain` resource |
| name, the API will return all destination domains configured to that |
| domain |
| |
| .... |
| ["firstDestination.com", "secondDestination.com"] |
| .... |
| |
| Response codes: |
| |
| * 200: OK |
| * 400: The `fromDomain` resource name is invalid |
| * 404: The `fromDomain` resource name is not found |
| |
| ==== Adding a domain mapping |
| |
| .... |
| curl -XPUT http://ip:port/domainMappings/sourceDomain.tld |
| .... |
| |
| Body: |
| |
| .... |
| destination.tld |
| .... |
| |
| With `sourceDomain.tld` as the value passed to `fromDomain` resource |
| name, the API will add a destination domain specified in the body to |
| that domain |
| |
| Response codes: |
| |
| * 204: OK |
| * 400: The `fromDomain` resource name is invalid |
| * 400: The destination domain specified in the body is invalid |
| |
| Be aware that no checks to find possible loops that would result of this creation will be performed. |
| |
| ==== Removing a domain mapping |
| |
| .... |
| curl -XDELETE http://ip:port/domainMappings/sourceDomain.tld |
| .... |
| |
| Body: |
| |
| .... |
| destination.tld |
| .... |
| |
| With `sourceDomain.tld` as the value passed to `fromDomain` resource |
| name, the API will remove a destination domain specified in the body |
| mapped to that domain |
| |
| Response codes: |
| |
| * 204: OK |
| * 400: The `fromDomain` resource name is invalid |
| * 400: The destination domain specified in the body is invalid |
| |
| === Regex mapping |
| |
| You can use *webadmin* to create regex mappings. |
| |
| A regex mapping contains a mapping source and a Java Regular Expression |
| (regex) in String as the mapping value. Everytime, if a mail containing |
| a recipient matched with the mapping source, then that mail will be |
| re-routed to a new recipient address which is re written by the regex. |
| |
| This feature uses xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table] |
| and requires the |
| https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java[RecipientRewriteTable |
| API] to be configured. |
| |
| ==== Adding a regex mapping |
| |
| .... |
| POST /mappings/regex/mappingSource/targets/regex |
| .... |
| |
| Where: |
| |
| * the `mappingSource` is the path parameter represents for the Regex |
| Mapping mapping source |
| * the `regex` is the path parameter represents for the Regex Mapping |
| regex |
| |
| The route will add a regex mapping made from `mappingSource` and `regex` |
| to RecipientRewriteTable. |
| |
| Example: |
| |
| .... |
| curl -XPOST http://ip:port/mappings/regex/james@domain.tld/targets/james@.*:james-intern@james.org |
| .... |
| |
| Response codes: |
| |
| * 204: Mapping added successfully. |
| * 400: Invalid `mappingSource` path parameter. |
| * 400: Invalid `regex` path parameter. |
| |
| Be aware that no checks to find possible loops that would result of this creation will be performed. |
| |
| ==== Removing a regex mapping |
| |
| .... |
| DELETE /mappings/regex/{mappingSource}/targets/{regex} |
| .... |
| |
| Where: |
| |
| * the `mappingSource` is the path parameter representing the Regex |
| Mapping mapping source |
| * the `regex` is the path parameter representing the Regex Mapping regex |
| |
| The route will remove the regex mapping made from `regex` from the |
| mapping source `mappingSource` to RecipientRewriteTable. |
| |
| Example: |
| |
| .... |
| curl -XDELETE http://ip:port/mappings/regex/james@domain.tld/targets/[O_O]:james-intern@james.org |
| .... |
| |
| Response codes: |
| |
| * 204: Mapping deleted successfully. |
| * 400: Invalid `mappingSource` path parameter. |
| * 400: Invalid `regex` path parameter. |
| |
| === Address Mappings |
| |
| You can use *webadmin* to define address mappings. |
| |
| When a specific email is sent to the base mail address, every |
| destination addresses will receive it. |
| |
| This feature uses xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table] |
| and requires the |
| https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java[RecipientRewriteTable |
| mailet] to be configured. |
| |
| Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected. |
| |
| Please use address mappings with caution, as it’s not a typed address. |
| If you know the type of your address (forward, alias, domain, group, |
| etc), prefer using the corresponding routes to those types. |
| |
| Here are the following actions available on address mappings: |
| |
| ==== Add an address mapping |
| |
| .... |
| curl -XPOST http://ip:port/mappings/address/{mappingSource}/targets/{destinationAddress} |
| .... |
| |
| Add an address mapping to the Recipients rewrite table |
| Mapping source is the value of \{mappingSource} Mapping destination is |
| the value of \{destinationAddress} Type of mapping destination is |
| Address |
| |
| Response codes: |
| |
| * 204: Action successfully performed |
| * 400: Invalid parameters |
| * 409: The addition of the address mapping would lead to a loop and thus cannot be performed |
| |
| ==== Remove an address mapping |
| |
| .... |
| curl -XDELETE http://ip:port/mappings/address/{mappingSource}/targets/{destinationAddress} |
| .... |
| |
| * Remove an address mapping from the Recipients rewrite table |
| * Mapping source is the value of `mappingSource` |
| * Mapping destination is the value of `destinationAddress` |
| * Type of mapping destination is Address |
| |
| Response codes: |
| |
| * 204: Action successfully performed |
| * 400: Invalid parameters |
| |
| === List all mappings |
| |
| .... |
| curl -XGET http://ip:port/mappings |
| .... |
| |
| Get all mappings from the |
| xref:{xref-base}/architecture/index.adoc#_recipient_rewrite_tables[Recipients rewrite table]. |
| |
| Response body: |
| |
| .... |
| { |
| "alias@domain.tld": [ |
| { |
| "type": "Alias", |
| "mapping": "user@domain.tld" |
| }, |
| { |
| "type": "Group", |
| "mapping": "group-user@domain.tld" |
| } |
| ], |
| "aliasdomain.tld": [ |
| { |
| "type": "Domain", |
| "mapping": "realdomain.tld" |
| } |
| ], |
| "group@domain.tld": [ |
| { |
| "type": "Address", |
| "mapping": "user@domain.tld" |
| } |
| ] |
| } |
| .... |
| |
| Response code: |
| |
| * 200: OK |
| |
| === Listing User Mappings |
| |
| This endpoint allows receiving all mappings originating from a corresponding user. |
| |
| .... |
| curl -XGET http://ip:port/mappings/user/{userAddress} |
| .... |
| |
| Return all mappings of a user where: |
| |
| * `userAddress`: is the selected user |
| |
| Response body: |
| |
| .... |
| [ |
| { |
| "type": "Address", |
| "mapping": "user123@domain.tld" |
| }, |
| { |
| "type": "Alias", |
| "mapping": "aliasuser123@domain.tld" |
| }, |
| { |
| "type": "Group", |
| "mapping": "group123@domain.tld" |
| } |
| ] |
| .... |
| |
| Response codes: |
| |
| * 200: OK |
| * 400: Invalid parameter value |
| |
| === Listing sources for a mapping |
| |
| This endpoint allows receiving all mappings pointing to a corresponding user. |
| |
| .... |
| curl -XGET http://ip:port/mappings/sources/{userAddress}?type={type} |
| .... |
| |
| Return all mappings of a user where: |
| |
| * `userAddress`: is the selected user |
| * `type`: Type of the mapping. One of `group`, `forward`, `address`, `alias`. Compulsory. |
| |
| Response body: |
| |
| .... |
| ["group1@domain.tld","group2@domain.tld"] |
| .... |
| |
| Response codes: |
| |
| * 200: OK |
| * 400: Invalid parameter value |
| |
| === Deleting sources for a mapping |
| |
| This endpoint allows deleting all mappings pointing to a corresponding user. |
| |
| .... |
| curl -XDELETE http://ip:port/mappings/sources/{userAddress}?type={type} |
| .... |
| |
| Deletes all mappings of a user where: |
| |
| * `userAddress`: is the selected user |
| * `type`: Type of the mapping. One of `group`, `forward`, `address`, `alias`. Compulsory. |
| |
| Response codes: |
| |
| * 204: OK |
| * 400: Invalid parameter value |
| |
| == Administrating mail repositories |
| |
| === Create a mail repository |
| |
| .... |
| curl -XPUT http://ip:port/mailRepositories/{encodedPathOfTheRepository}?protocol={someProtocol} |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of the created mail repository. Example: |
| |
| .... |
| curl -XPUT http://ip:port/mailRepositories/mailRepo?protocol=file |
| .... |
| |
| Response codes: |
| |
| * 204: The repository is created |
| |
| === Listing mail repositories |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories |
| .... |
| |
| The answer looks like: |
| |
| .... |
| [ |
| { |
| "repository": "var/mail/error/", |
| "path": "var%2Fmail%2Ferror%2F" |
| }, |
| { |
| "repository": "var/mail/relay-denied/", |
| "path": "var%2Fmail%2Frelay-denied%2F" |
| }, |
| { |
| "repository": "var/mail/spam/", |
| "path": "var%2Fmail%2Fspam%2F" |
| }, |
| { |
| "repository": "var/mail/address-error/", |
| "path": "var%2Fmail%2Faddress-error%2F" |
| } |
| ] |
| .... |
| |
| You can use `id`, the encoded URL of the repository, to access it in |
| later requests. |
| |
| Response codes: |
| |
| * 200: The list of mail repositories |
| |
| === Getting additional information for a mail repository |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/{encodedPathOfTheRepository} |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of an existing mail repository. Example: |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F |
| .... |
| |
| The answer looks like: |
| |
| .... |
| { |
| "repository": "var/mail/error/", |
| "path": "mail%2Ferror%2F", |
| "size": 243 |
| } |
| .... |
| |
| Response codes: |
| |
| * 200: Additonnal information for that repository |
| * 404: This repository can not be found |
| |
| === Listing mails contained in a mail repository |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of an existing mail repository. Example: |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails |
| .... |
| |
| The answer will contains all mailKey contained in that repository. |
| |
| .... |
| [ |
| "mail-key-1", |
| "mail-key-2", |
| "mail-key-3" |
| ] |
| .... |
| |
| Note that this can be used to read mail details. |
| |
| You can pass additional URL parameters to this call in order to limit |
| the output: |
| |
| - limit: no more elements than the specified limit will be |
| returned. This needs to be strictly positive. If no value is specified, |
| no limit will be applied. |
| - offset: allow to skip elements. This needs to be positive. Default value is zero. |
| |
| Example: |
| |
| .... |
| curl -XGET 'http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails?limit=100&offset=500' |
| .... |
| |
| You can also pass the following additional URL parameters to filter results: |
| |
| - updatedBefore: filter mails by mail last updated. For example, if the value is `2d` and the current time is `21-12-2024 13:00:00`, the condition would be: last updated < 19-12-2024 13:00:00 (currentTime - `2d`). Some other value samples: `2d`, `2 days`, `2h`, `2 hours`. |
| - updatedAfter: filter mails by mail last updated. For example, if the value is `2d` and the current time is `21-12-2024 13:00:00`, the condition would be: last updated > 19-12-2024 13:00:00 (currentTime - `2d`). Some other value samples: `2d`, `2 days`, `2h`, `2 hours`. |
| - sender: filter mails by mail sender. If the input value is in the special format `*@domain.com`, mails are filters by domain. |
| - recipient: filter by recipient. If the input value is in the special format `*@domain.com`, mails are filters by domain. |
| - remoteAddress: filter mails by remoteAddress. |
| - remoteHost: filter mails by remoteHost. |
| |
| Example: |
| |
| .... |
| curl -XGET /mailRepositories/var%2Fmail%2Ferror%2F/mails?updatedBefore=2d&remoteAddress=128.45.67.89 |
| .... |
| |
| Response codes: |
| |
| * 200: The list of mail keys contained in that mail repository |
| * 400: Invalid parameters |
| * 404: This repository can not be found |
| |
| === Reading/downloading a mail details |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/mailKey |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of an existing mail repository. Resource name `mailKey` should be the |
| key of a mail stored in that repository. Example: |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/mail-key-1 |
| .... |
| |
| If the Accept header in the request is ``application/json'', then the |
| response looks like: |
| |
| .... |
| { |
| "name": "mail-key-1", |
| "sender": "sender@domain.com", |
| "recipients": ["recipient1@domain.com", "recipient2@domain.com"], |
| "state": "address-error", |
| "error": "A small message explaining what happened to that mail...", |
| "remoteHost": "111.222.333.444", |
| "remoteAddr": "127.0.0.1", |
| "lastUpdated": null |
| } |
| .... |
| |
| If the Accept header in the request is ``message/rfc822'', then the |
| response will be the _eml_ file itself. |
| |
| Additional query parameter `additionalFields` add the existing |
| information to the response for the supported values (only work with |
| ``application/json'' Accept header): |
| |
| * attributes |
| * headers |
| * textBody |
| * htmlBody |
| * messageSize |
| * perRecipientsHeaders |
| |
| .... |
| curl -XGET http://ip:port/mailRepositories/file%3A%2F%2Fvar%2Fmail%2Ferror%2F/mails/mail-key-1?additionalFields=attributes,headers,textBody,htmlBody,messageSize,perRecipientsHeaders |
| .... |
| |
| Give the following kind of response: |
| |
| .... |
| { |
| "name": "mail-key-1", |
| "sender": "sender@domain.com", |
| "recipients": ["recipient1@domain.com", "recipient2@domain.com"], |
| "state": "address-error", |
| "error": "A small message explaining what happened to that mail...", |
| "remoteHost": "111.222.333.444", |
| "remoteAddr": "127.0.0.1", |
| "lastUpdated": null, |
| "attributes": { |
| "name2": "value2", |
| "name1": "value1" |
| }, |
| "perRecipientsHeaders": { |
| "third@party": { |
| "headerName1": [ |
| "value1", |
| "value2" |
| ], |
| "headerName2": [ |
| "value3", |
| "value4" |
| ] |
| } |
| }, |
| "headers": { |
| "headerName4": [ |
| "value6", |
| "value7" |
| ], |
| "headerName3": [ |
| "value5", |
| "value8" |
| ] |
| }, |
| "textBody": "My body!!", |
| "htmlBody": "My <em>body</em>!!", |
| "messageSize": 42424242 |
| } |
| .... |
| |
| Response codes: |
| |
| * 200: Details of the mail |
| * 404: This repository or mail can not be found |
| |
| === Removing a mail from a mail repository |
| |
| .... |
| curl -XDELETE http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/mailKey |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of an existing mail repository. Resource name `mailKey` should be the |
| key of a mail stored in that repository. Example: |
| |
| .... |
| curl -XDELETE http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/mail-key-1 |
| .... |
| |
| Response codes: |
| |
| * 204: This mail no longer exists in this repository |
| * 404: This repository can not be found |
| |
| === Removing all mails from a mail repository |
| |
| .... |
| curl -XDELETE http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of an existing mail repository. Example: |
| |
| .... |
| curl -XDELETE http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Task generation succeeded. Corresponding task id is returned. |
| * 404: Could not find that mail repository |
| |
| The scheduled task will have the following type `clear-mail-repository` |
| and the following `additionalInformation`: |
| |
| .... |
| { |
| "mailRepositoryPath":"var/mail/error/", |
| "initialCount": 243, |
| "remainingCount": 17 |
| } |
| .... |
| |
| === Reprocessing mails from a mail repository |
| |
| Sometime, you want to re-process emails stored in a mail repository. For |
| instance, you can make a configuration error, or there can be a James |
| bug that makes processing of some mails fail. Those mail will be stored |
| in a mail repository. Once you solved the problem, you can reprocess |
| them. |
| |
| To reprocess mails from a repository: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails?action=reprocess |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource path |
| of an existing mail repository. Example: |
| |
| For instance: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails?action=reprocess |
| .... |
| |
| Additional query parameters are supported: |
| |
| - `queue` allows you to |
| target the mail queue you want to enqueue the mails in. Defaults to |
| `spool`. |
| - `processor` allows you to overwrite the state of the |
| reprocessing mails, and thus select the processors they will start their |
| processing in. Defaults to the `state` field of each processed email. |
| - `consume` (boolean defaulting to `true`) whether the reprocessing should consume the mail in its originating mail repository. Passing |
| this value to `false` allows non destructive reprocessing as you keep a copy of the email in the mail repository and can be valuable |
| when debugging. |
| - `limit` (integer value. Optional, default is empty). It enables to limit the count of elements reprocessed. |
| If unspecified the count of the processed elements is unbounded. |
| - `maxRetries` Optional integer, defaults to no max retries limit. Only processed emails that had been retried less |
| than this value. Ignored by default. |
| |
| redeliver_group_events |
| |
| .... |
| curl -XPATCH 'http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails?action=reprocess&processor=transport&queue=spool' |
| .... |
| |
| Note that the `action` query parameter is compulsary and can only take |
| value `reprocess`. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Task generation succeeded. Corresponding task id is returned. |
| * 404: Could not find that mail repository |
| |
| The scheduled task will have the following type `reprocessing-all` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "mailRepositoryPath":"var/mail/error/", |
| "targetQueue":"spool", |
| "targetProcessor":"transport", |
| "initialCount": 243, |
| "remainingCount": 17 |
| } |
| .... |
| |
| === Reprocessing a specific mail from a mail repository |
| |
| To reprocess a specific mail from a mail repository: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/mailKey?action=reprocess |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the resource id of |
| an existing mail repository. Resource name `mailKey` should be the key |
| of a mail stored in that repository. Example: |
| |
| For instance: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/name1?action=reprocess |
| .... |
| |
| Additional query parameters are supported: |
| |
| - `queue` allows you to |
| target the mail queue you want to enqueue the mails in. Defaults to |
| `spool`. |
| - `processor` allows you to overwrite the state of the |
| reprocessing mails, and thus select the processors they will start their |
| processing in. Defaults to the `state` field of each processed email. |
| - `consume` (boolean defaulting to `true`) whether the reprocessing should consume the mail in its originating mail repository. Passing |
| this value to `false` allows non destructive reprocessing as you keep a copy of the email in the mail repository and can be valuable |
| when debugging. |
| |
| While `processor` being an optional parameter, not specifying it will |
| result reprocessing the mails in their current state |
| (https://james.apache.org/server/feature-mailetcontainer.html#Processors[see |
| documentation about processors and state]). Consequently, only few cases |
| will give a different result, definitively storing them out of the mail |
| repository. |
| |
| For instance: |
| |
| .... |
| curl -XPATCH 'http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/name1?action=reprocess&processor=transport&queue=spool' |
| .... |
| |
| Note that the `action` query parameter is compulsary and can only take |
| value `reprocess`. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Task generation succeeded. Corresponding task id is returned. |
| * 404: Could not find that mail repository |
| |
| The scheduled task will have the following type `reprocessing-one` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "mailRepositoryPath":"var/mail/error/", |
| "targetQueue":"spool", |
| "targetProcessor":"transport", |
| "mailKey":"name1" |
| } |
| .... |
| |
| === Moving mails from a mail repository to another |
| |
| To move all mails from one repository to another: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails \ |
| -d '{"mailRepository": "/var/mail/error-saved"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the URL-encoded path of an existing mail |
| repository. The request body must contain the path of an existing target mail repository. |
| |
| For instance: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails \ |
| -d '{"mailRepository": "var/mail/error-saved"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Response codes: |
| |
| * 204: Mails were successfully moved. |
| * 400: The target repository does not exist, or the request body is invalid. |
| * 404: The source repository does not exist. |
| |
| === Moving a specific mail to another repository |
| |
| To move a specific mail from one repository to another: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/{mailKey} \ |
| -d '{"mailRepository": "/var/mail/error-saved"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Resource name `encodedPathOfTheRepository` should be the URL-encoded path of an existing mail |
| repository. Resource name `mailKey` should be the key of a mail stored in that repository. |
| The request body must contain the path of an existing target mail repository. |
| |
| For instance: |
| |
| .... |
| curl -XPATCH http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/name1 \ |
| -d '{"mailRepository": "var/mail/error-saved"}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| Response codes: |
| |
| * 204: The mail was successfully moved (or the mail key was not found, in which case nothing is done). |
| * 400: The target repository does not exist, or the request body is invalid. |
| * 404: The source repository does not exist. |
| |
| == Administrating mail queues |
| |
| === Listing mail queues |
| |
| .... |
| curl -XGET http://ip:port/mailQueues |
| .... |
| |
| The answer looks like: |
| |
| .... |
| ["outgoing","spool"] |
| .... |
| |
| Response codes: |
| |
| * 200: The list of mail queues |
| |
| === Getting a mail queue details |
| |
| .... |
| curl -XGET http://ip:port/mailQueues/{mailQueueName} |
| .... |
| |
| Resource name `mailQueueName` is the name of a mail queue, this command |
| will return the details of the given mail queue. For instance: |
| |
| .... |
| {"name":"outgoing","size":0} |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| * 400: Mail queue is not valid |
| * 404: The mail queue does not exist |
| |
| === Listing the mails of a mail queue |
| |
| .... |
| curl -XGET http://ip:port/mailQueues/{mailQueueName}/mails |
| .... |
| |
| Additional URL query parameters: |
| |
| * `limit`: Maximum number of mails returned in a single call. Only |
| strictly positive integer values are accepted. Example: |
| |
| .... |
| curl -XGET http://ip:port/mailQueues/{mailQueueName}/mails?limit=100 |
| .... |
| |
| The answer looks like: |
| |
| .... |
| [{ |
| "name": "Mail1516976156284-8b3093b9-eebf-4c40-9c26-1450f4fcdc3c-to-test.com", |
| "sender": "user@james.linagora.com", |
| "recipients": ["someone@test.com"], |
| "nextDelivery": "1969-12-31T23:59:59.999Z" |
| }] |
| .... |
| |
| Response codes: |
| |
| * 200: Success |
| * 400: Mail queue is not valid or limit is invalid |
| * 404: The mail queue does not exist |
| |
| === Deleting mails from a mail queue |
| |
| .... |
| curl -XDELETE http://ip:port/mailQueues/{mailQueueName}/mails?sender=senderMailAddress |
| .... |
| |
| This request should have exactly one query parameter from the following |
| list: |
| |
| * sender: which is a mail address (i.e. sender@james.org) |
| * name: which is a string |
| * recipient: which is a mail address (i.e. recipient@james.org) |
| |
| The mails from the given mail queue matching the query parameter will be |
| deleted. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Task generation succeeded. Corresponding task id is returned. |
| * 400: Invalid request |
| * 404: The mail queue does not exist |
| |
| The scheduled task will have the following type |
| `delete-mails-from-mail-queue` and the following |
| `additionalInformation`: |
| |
| .... |
| { |
| "queue":"outgoing", |
| "initialCount":10, |
| "remainingCount": 5, |
| "sender": "sender@james.org", |
| "name": "Java Developer", |
| "recipient: "recipient@james.org" |
| } |
| .... |
| |
| === Clearing a mail queue |
| |
| .... |
| curl -XDELETE http://ip:port/mailQueues/{mailQueueName}/mails |
| .... |
| |
| All mails from the given mail queue will be deleted. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: Task generation succeeded. Corresponding task id is returned. |
| * 400: Invalid request |
| * 404: The mail queue does not exist |
| |
| The scheduled task will have the following type `clear-mail-queue` and |
| the following `additionalInformation`: |
| |
| .... |
| { |
| "queue":"outgoing", |
| "initialCount":10, |
| "remainingCount": 0 |
| } |
| .... |
| |
| === Flushing mails from a mail queue |
| |
| .... |
| curl -XPATCH http://ip:port/mailQueues/{mailQueueName}?delayed=true \ |
| -d '{"delayed": false}' \ |
| -H "Content-Type: application/json" |
| .... |
| |
| This request should have the query parameter _delayed_ set to _true_, in |
| order to indicate only delayed mails are affected. The payload should |
| set the `delayed` field to false inorder to remove the delay. This is |
| the only supported combination, and it performs a flush. |
| |
| The mails delayed in the given mail queue will be flushed. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 204: Success (No content) |
| * 400: Invalid request |
| * 404: The mail queue does not exist |
| |
| === RabbitMQ republishing a mail queue from {backend-name} |
| |
| .... |
| curl -XPOST 'http://ip:port/mailQueues/{mailQueueName}?action=RepublishNotProcessedMails&olderThan=1d' |
| .... |
| |
| This method is specific to the distributed flavor of James, which relies |
| on {backend-name} and RabbitMQ for implementing a mail queue. In case of a |
| RabbitMQ crash resulting in a loss of messages, this task can be |
| launched to repopulate the `mailQueueName` queue in RabbitMQ using the |
| information stored in {backend-name}. |
| |
| The `olderThan` parameter is mandatory. It filters the mails to be |
| restored, by taking into account only the mails older than the given |
| value. The expected value should be expressed in the following format: |
| `Nunit`. `N` should be strictly positive. `unit` could be either in the |
| short form (`h`, `d`, `w`, etc.), or in the long form (`day`, `week`, |
| `month`, etc.). |
| |
| Examples: |
| |
| * `5h` |
| * `7d` |
| * `1y` |
| |
| Response codes: |
| |
| * 201: Task created |
| * 400: Invalid request |
| |
| The response body contains the id of the republishing task. |
| `{ "taskId": "a650a66a-5984-431e-bdad-f1baad885856" }` |
| |
| include::{admin-mail-queues-extend}[] |
| |
| == Sending email over webAdmin |
| |
| .... |
| curl -XPOST /mail-transfer-service |
| |
| {MIME message} |
| .... |
| |
| Will send the following email to the recipients specified in the MIME message. |
| |
| The `{MIME message}` payload must match `message/rfc822` format. |
| |
| == Event Dead Letter |
| |
| The EventBus allows to register `group listeners' that are called in a |
| distributed fashion. These group listeners enable the implementation of |
| some advanced mailbox manager feature like indexing, spam reporting, |
| quota management and the like. |
| |
| Upon exceptions, a bounded number of retries are performed (with |
| exponential backoff delays). If after those retries the listener is |
| still failing, then the event will be stored in the ``Event Dead |
| Letter''. This API allows diagnosing issues, as well as performing event |
| replay. |
| |
| === Listing mailbox listener groups |
| |
| This endpoint allows discovering the list of mailbox listener groups. |
| |
| .... |
| curl -XGET http://ip:port/events/deadLetter/groups |
| .... |
| |
| Will return a list of group names that can be further used to interact |
| with the dead letter API: |
| |
| .... |
| ["org.apache.james.mailbox.events.EventBusTestFixture$GroupA", "org.apache.james.mailbox.events.GenericGroup-abc"] |
| .... |
| |
| Response codes: |
| |
| * 200: Success. A list of group names is returned. |
| |
| === Listing failed events |
| |
| This endpoint allows listing failed events for a given group: |
| |
| .... |
| curl -XGET http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA |
| .... |
| |
| Will return a list of insertionIds: |
| |
| .... |
| ["6e0dd59d-660e-4d9b-b22f-0354479f47b4", "58a8f59d-660e-4d9b-b22f-0354486322a2"] |
| .... |
| |
| Response codes: |
| |
| * 200: Success. A list of insertion ids is returned. |
| * 400: Invalid group name |
| |
| === Getting event details |
| |
| .... |
| curl -XGET http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA/6e0dd59d-660e-4d9b-b22f-0354479f47b4 |
| .... |
| |
| Will return the full JSON associated with this event. |
| |
| Response codes: |
| |
| * 200: Success. A JSON representing this event is returned. |
| * 400: Invalid group name or `insertionId` |
| * 404: No event with this `insertionId` |
| |
| === Deleting an event |
| |
| .... |
| curl -XDELETE http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA/6e0dd59d-660e-4d9b-b22f-0354479f47b4 |
| .... |
| |
| Will delete this event. |
| |
| Response codes: |
| |
| * 204: Success |
| * 400: Invalid group name or `insertionId` |
| |
| === Deleting all events of a group |
| |
| .... |
| curl -XDELETE http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA |
| .... |
| |
| Will delete all events of this group. |
| |
| Response codes: |
| |
| * 204: Success |
| * 400: Invalid group name |
| |
| === Redeliver all events |
| |
| .... |
| curl -XPOST http://ip:port/events/deadLetter?action=reDeliver |
| .... |
| |
| Additional query parameters are supported: |
| |
| - `limit` (integer value. Optional, default is empty). It enables to limit the count of elements redelivered. |
| If unspecified the count of the processed elements is unbounded |
| |
| For instance: |
| |
| .... |
| curl -XPOST http://ip:port/events/deadLetter?action=reDeliver&limit=10 |
| .... |
| |
| Will create a task that will attempt to redeliver all events stored in |
| ``Event Dead Letter''. If successful, redelivered events will then be |
| removed from ``Dead Letter''. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: the taskId of the created task |
| * 400: Invalid action argument |
| |
| === Redeliver group events |
| |
| .... |
| curl -XPOST http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA?action=reDeliver |
| .... |
| |
| Will create a task that will attempt to redeliver all events of a |
| particular group stored in ``Event Dead Letter''. If successful, |
| redelivered events will then be removed from ``Dead Letter''. |
| |
| Additional query parameters are supported: |
| |
| - `limit` (integer value. Optional, default is empty). It enables to limit the count of elements redelivered. |
| If unspecified the count of the processed elements is unbounded |
| |
| For instance: |
| |
| .... |
| curl -XPOST http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA?action=reDeliver&limit=10 |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: the taskId of the created task |
| * 400: Invalid group name or action argument |
| |
| === Redeliver a single event |
| |
| .... |
| curl -XPOST http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA/6e0dd59d-660e-4d9b-b22f-0354479f47b4?action=reDeliver |
| .... |
| |
| Will create a task that will attempt to redeliver a single event of a |
| particular group stored in ``Event Dead Letter''. If successful, |
| redelivered event will then be removed from ``Dead Letter''. |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response codes: |
| |
| * 201: the taskId of the created task |
| * 400: Invalid group name, insertion id or action argument |
| * 404: No event with this insertionId |
| |
| == Deleted Messages Vault |
| |
| The `Deleted Message Vault plugin' allows you to keep users deleted |
| messages during a given retention time. This set of routes allow you to |
| _restore_ users deleted messages or export them in an archive. |
| |
| To move deleted messages in the vault, you need to specifically |
| configure the DeletedMessageVault PreDeletionHook. |
| |
| === Browse Deleted Messages |
| |
| Deleted messages of a specific user can be listed by calling the following endpoint: |
| |
| .... |
| curl -XPOST http://ip:port/deletedMessages/users/user@domain.ext/messages |
| |
| { |
| "combinator": "and", |
| "criteria": [ |
| { |
| "fieldName": "subject", |
| "operator": "containsIgnoreCase", |
| "value": "Apache James" |
| } |
| ] |
| } |
| .... |
| |
| To retrieve a specific message by its id: |
| |
| .... |
| { |
| "combinator": "and", |
| "criteria": [ |
| { |
| "fieldName": "messageId", |
| "operator": "equals", |
| "value": "3294a976-ce63-491e-bd52-1b6f465ed7a2" |
| } |
| ] |
| } |
| .... |
| |
| The query body follows the same structure as link:#_restore_deleted_messages[Restore Deleted Messages]. |
| Pass an empty criteria list to retrieve all deleted messages: |
| |
| .... |
| { |
| "combinator": "and", |
| "criteria": [] |
| } |
| .... |
| |
| Response code: |
| |
| * 200: List of deleted messages matching the query |
| * 400: Bad request: |
| ** user parameter is invalid |
| ** can not parse the JSON body |
| ** Json query object contains unsupported operator, fieldName |
| ** Json query object values violate parsing rules |
| * 404: User not found |
| |
| Response body is a JSON array: |
| |
| .... |
| [ |
| { |
| "messageId": "3294a976-ce63-491e-bd52-1b6f465ed7a2", |
| "originMailboxes": [ |
| "02874f7c-d10e-102f-acda-0015176f7922" |
| ], |
| "owner": "user@domain.ext", |
| "deliveryDate": "2014-10-30T14:12:00Z", |
| "deletionDate": "2015-10-20T09:08:00Z", |
| "sender": "sender@apache.org", |
| "recipients": [ |
| "recipient@james.org" |
| ], |
| "subject": "Apache James", |
| "hasAttachment": false, |
| "size": 1234 |
| } |
| ] |
| .... |
| |
| === Restore Deleted Messages |
| |
| Deleted messages of a specific user can be restored by calling the |
| following endpoint: |
| |
| .... |
| curl -XPOST http://ip:port/deletedMessages/users/userToRestore@domain.ext?action=restore |
| |
| { |
| "combinator": "and", |
| "criteria": [ |
| { |
| "fieldName": "subject", |
| "operator": "containsIgnoreCase", |
| "value": "Apache James" |
| }, |
| { |
| "fieldName": "deliveryDate", |
| "operator": "beforeOrEquals", |
| "value": "2014-10-30T14:12:00Z" |
| }, |
| { |
| "fieldName": "deletionDate", |
| "operator": "afterOrEquals", |
| "value": "2015-10-20T09:08:00Z" |
| }, |
| { |
| "fieldName": "recipients"," |
| "operator": "contains"," |
| "value": "recipient@james.org" |
| }, |
| { |
| "fieldName": "hasAttachment", |
| "operator": "equals", |
| "value": "false" |
| }, |
| { |
| "fieldName": "sender", |
| "operator": "equals", |
| "value": "sender@apache.org" |
| }, |
| { |
| "fieldName": "originMailboxes", |
| "operator": "contains", |
| "value": "02874f7c-d10e-102f-acda-0015176f7922" |
| } |
| ] |
| }; |
| .... |
| |
| The requested Json body is made from a list of criterion objects which |
| have the following structure: |
| |
| .... |
| { |
| "fieldName": "supportedFieldName", |
| "operator": "supportedOperator", |
| "value": "A plain string representing the matching value of the corresponding field" |
| } |
| .... |
| |
| Deleted Messages which are matched with the *all* criterion in the query |
| body will be restored. Here are a list of supported fieldName for the |
| restoring: |
| |
| * subject: represents for deleted message `subject` field matching. |
| Supports below string operators: |
| ** contains |
| ** containsIgnoreCase |
| ** equals |
| ** equalsIgnoreCase |
| * deliveryDate: represents for deleted message `deliveryDate` field |
| matching. Tested value should follow the right date time with zone |
| offset format (ISO-8601) like `2008-09-15T15:53:00+05:00` or |
| `2008-09-15T15:53:00Z` Supports below date time operators: |
| ** beforeOrEquals: is the deleted message’s `deliveryDate` before or |
| equals the time of tested value. |
| ** afterOrEquals: is the deleted message’s `deliveryDate` after or |
| equals the time of tested value |
| * deletionDate: represents for deleted message `deletionDate` field |
| matching. Tested value & Supports operators: similar to `deliveryDate` |
| * sender: represents for deleted message `sender` field matching. Tested |
| value should be a valid mail address. Supports mail address operator: |
| ** equals: does the tested sender equal to the sender of the tested |
| deleted message ? + |
| * recipients: represents for deleted message `recipients` field |
| matching. Tested value should be a valid mail address. Supports list |
| mail address operator: |
| ** contains: does the tested deleted message’s recipients contain tested |
| recipient ? |
| * hasAttachment: represents for deleted message `hasAttachment` field |
| matching. Tested value could be `false` or `true`. Supports boolean |
| operator: |
| ** equals: does the tested deleted message’s hasAttachment property |
| equal to the tested hasAttachment value? |
| * originMailboxes: represents for deleted message `originMailboxes` |
| field matching. Tested value is a string serialized of mailbox id. |
| Supports list mailbox id operators: |
| ** contains: does the tested deleted message’s originMailbox ids contain |
| tested mailbox id ? |
| * messageId: represents for deleted message `messageId` field matching. |
| Tested value is a string serialized message id. Supports string operator: |
| ** equals: does the tested deleted message’s messageId equal the tested |
| value? |
| |
| Messages in the Deleted Messages Vault of a specified user that are |
| matched with Query Json Object in the body will be appended to his |
| `Restored-Messages' mailbox, which will be created if needed. |
| |
| *Note*: |
| |
| * Query parameter `action` is required and should have the value |
| `restore` to represent the restoring feature. Otherwise, a bad request |
| response will be returned |
| * Query parameter `action` is case sensitive |
| * fieldName & operator passed to the routes are case sensitive |
| * Currently, we only support query combinator `and` value, otherwise, |
| requests will be rejected |
| * If you only want to restore by only one criterion, the json body could |
| be simplified to a single criterion: |
| |
| .... |
| { |
| "fieldName": "subject", |
| "operator": "containsIgnoreCase", |
| "value": "Apache James" |
| } |
| .... |
| |
| * For restoring all deleted messages, passing a query json with an empty |
| criterion list to represent `matching all deleted messages`: |
| |
| .... |
| { |
| "combinator": "and", |
| "criteria": [] |
| } |
| .... |
| |
| * For limiting the number of restored messages, you can use the `limit` query property: |
| |
| .... |
| { |
| "combinator": "and", |
| "limit": 99 |
| "criteria": [] |
| } |
| .... |
| |
| *Warning*: Current web-admin uses `US` locale as the default. Therefore, |
| there might be some conflicts when using String `containsIgnoreCase` |
| comparators to apply on the String data of other special locales stored |
| in the Vault. More details at |
| https://issues.apache.org/jira/browse/MAILBOX-384[JIRA] |
| |
| Response code: |
| |
| * 201: Task for restoring deleted has been created |
| * 400: Bad request: |
| ** action query param is not present |
| ** action query param is not a valid action |
| ** user parameter is invalid |
| ** can not parse the JSON body |
| ** Json query object contains unsupported operator, fieldName |
| ** Json query object values violate parsing rules |
| * 404: User not found |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| The scheduled task will have the following type |
| `deleted-messages-restore` and the following `additionalInformation`: |
| |
| .... |
| { |
| "successfulRestoreCount": 47, |
| "errorRestoreCount": 0, |
| "user": "userToRestore@domain.ext" |
| } |
| .... |
| |
| while: |
| |
| * successfulRestoreCount: number of restored messages |
| * errorRestoreCount: number of messages that failed to restore |
| * user: owner of deleted messages need to restore |
| |
| === Export Deleted Messages |
| |
| Retrieve deleted messages matched with requested query from an user then |
| share the content to a targeted mail address (exportTo) |
| |
| .... |
| curl -XPOST 'http://ip:port/deletedMessages/users/userExportFrom@domain.ext?action=export&exportTo=userReceiving@domain.ext' |
| |
| BODY: is the json query has the same structure with Restore Deleted Messages section |
| .... |
| |
| *Note*: Json query passing into the body follows the same rules & |
| restrictions like in link:#_restore_deleted_messages[Restore Deleted |
| Messages] |
| |
| Response code: |
| |
| * 201: Task for exporting has been created |
| * 400: Bad request: |
| ** exportTo query param is not present |
| ** exportTo query param is not a valid mail address |
| ** action query param is not present |
| ** action query param is not a valid action |
| ** user parameter is invalid |
| ** can not parse the JSON body |
| ** Json query object contains unsupported operator, fieldName |
| ** Json query object values violate parsing rules |
| * 404: User not found |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| The scheduled task will have the following type |
| `deleted-messages-export` and the following `additionalInformation`: |
| |
| .... |
| { |
| "userExportFrom": "userToRestore@domain.ext", |
| "exportTo": "userReceiving@domain.ext", |
| "totalExportedMessages": 1432 |
| } |
| .... |
| |
| while: |
| |
| * userExportFrom: export deleted messages from this user |
| * exportTo: content of deleted messages have been shared to this mail |
| address |
| * totalExportedMessages: number of deleted messages match with |
| json query, then being shared to sharee. |
| |
| === Purge Deleted Messages |
| |
| You can overwrite `retentionPeriod' configuration in |
| `deletedMessageVault' configuration file or use the default value of 1 |
| year. |
| |
| Purge all deleted messages older than the configured `retentionPeriod' |
| |
| .... |
| curl -XDELETE http://ip:port/deletedMessages?scope=expired |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response code: |
| |
| * 201: Task for purging has been created |
| * 400: Bad request: |
| ** action query param is not present |
| ** action query param is not a valid action |
| |
| You may want to call this endpoint on a regular basis. |
| |
| === Permanently Remove Deleted Message |
| |
| Delete a Deleted Message with `MessageId` |
| |
| .... |
| curl -XDELETE http://ip:port/deletedMessages/users/user@domain.ext/messages/3294a976-ce63-491e-bd52-1b6f465ed7a2 |
| .... |
| |
| link:#_endpoints_returning_a_task[More details about endpoints returning |
| a task]. |
| |
| Response code: |
| |
| * 201: Task for deleting message has been created |
| * 400: Bad request: |
| ** user parameter is invalid |
| ** messageId parameter is invalid |
| * 404: User not found |
| |
| The scheduled task will have the following type |
| `deleted-messages-delete` and the following `additionalInformation`: |
| |
| .... |
| { |
| "userName": "user@domain.ext", |
| "messageId": "3294a976-ce63-491e-bd52-1b6f465ed7a2" |
| } |
| .... |
| |
| while: - user: delete deleted messages from this user - deleteMessageId: |
| messageId of deleted messages will be delete |
| |
| == Administrating DLP Configuration |
| |
| DLP (stands for Data Leak Prevention) is supported by James. A DLP |
| matcher will, on incoming emails, execute regular expressions on email |
| sender, recipients or content, in order to report suspicious emails to |
| an administrator. WebAdmin can be used to manage these DLP rules on a |
| per `senderDomain` basis. |
| |
| `senderDomain` is domain of the sender of incoming emails, for example: |
| `apache.org`, `james.org`,… Each `senderDomain` correspond to a distinct |
| DLP configuration. |
| |
| === List DLP configuration by sender domain |
| |
| Retrieve a DLP configuration for corresponding `senderDomain`, a |
| configuration contains list of configuration items |
| |
| .... |
| curl -XGET http://ip:port/dlp/rules/{senderDomain} |
| .... |
| |
| Response codes: |
| |
| * 200: A list of dlp configuration items is returned |
| * 400: Invalid `senderDomain` or payload in request |
| * 404: The domain does not exist. |
| |
| This is an example of returned body. The rules field is a list of rules |
| as described below. |
| |
| .... |
| {"rules : [ |
| { |
| "id": "1", |
| "expression": "james.org", |
| "explanation": "Find senders or recipients containing james[any char]org", |
| "targetsSender": true, |
| "targetsRecipients": true, |
| "targetsContent": false |
| }, |
| { |
| "id": "2", |
| "expression": "Find senders containing apache[any char]org", |
| "explanation": "apache.org", |
| "targetsSender": true, |
| "targetsRecipients": false, |
| "targetsContent": false |
| } |
| ]} |
| .... |
| |
| === Store DLP configuration by sender domain |
| |
| Store a DLP configuration for corresponding `senderDomain`, if any item |
| of DLP configuration in the request is stored before, it will not be |
| stored anymore |
| |
| .... |
| curl -XPUT http://ip:port/dlp/rules/{senderDomain} |
| .... |
| |
| The body can contain a list of DLP configuration items formed by those |
| fields: - `id`(String) is mandatory, unique identifier of the |
| configuration item - `expression`(String) is mandatory, regular |
| expression to match contents of targets - `explanation`(String) is |
| optional, description of the configuration item - |
| `targetsSender`(boolean) is optional and defaults to false. If true, |
| `expression` will be applied to Sender and to From headers of the mail - |
| `targetsContent`(boolean) is optional and defaults to false. If true, |
| `expression` will be applied to Subject headers and textual bodies |
| (text/plain and text/html) of the mail - `targetsRecipients`(boolean) is |
| optional and defaults to false. If true, `expression` will be applied to |
| recipients of the mail |
| |
| This is an example of returned body. The rules field is a list of rules |
| as described below. |
| |
| .... |
| {"rules": [ |
| { |
| "id": "1", |
| "expression": "james.org", |
| "explanation": "Find senders or recipients containing james[any char]org", |
| "targetsSender": true, |
| "targetsRecipients": true, |
| "targetsContent": false |
| }, |
| { |
| "id": "2", |
| "expression": "Find senders containing apache[any char]org", |
| "explanation": "apache.org", |
| "targetsSender": true, |
| "targetsRecipients": false, |
| "targetsContent": false |
| } |
| ]} |
| .... |
| |
| Response codes: |
| |
| * 204: List of dlp configuration items is stored |
| * 400: Invalid `senderDomain` or payload in request |
| * 404: The domain does not exist. |
| |
| === Remove DLP configuration by sender domain |
| |
| Remove a DLP configuration for corresponding `senderDomain` |
| |
| .... |
| curl -XDELETE http://ip:port/dlp/rules/{senderDomain} |
| .... |
| |
| Response codes: |
| |
| * 204: DLP configuration is removed |
| * 400: Invalid `senderDomain` or payload in request |
| * 404: The domain does not exist. |
| |
| === Fetch a DLP configuration item by sender domain and rule id |
| |
| Retrieve a DLP configuration rule for corresponding `senderDomain` and a |
| `ruleId` |
| |
| .... |
| curl -XGET http://ip:port/dlp/rules/{senderDomain}/rules/{ruleId} |
| .... |
| |
| Response codes: |
| |
| * 200: A dlp configuration item is returned |
| * 400: Invalid `senderDomain` or payload in request |
| * 404: The domain and/or the rule does not exist. |
| |
| This is an example of returned body. |
| |
| .... |
| { |
| "id": "1", |
| "expression": "james.org", |
| "explanation": "Find senders or recipients containing james[any char]org", |
| "targetsSender": true, |
| "targetsRecipients": true, |
| "targetsContent": false |
| } |
| .... |
| |
| == Server administration |
| |
| === Reloading server certificates |
| |
| Certificates for TCP based protocols (IMAP, SMTP, POP3, LMTP and ManageSieve) can be updated at |
| runtime, without service interuption and without closing existing connections. |
| |
| In order to do so: |
| |
| - Generate / retrieve your cryptographic materials and replace the ones specified in James configuration. |
| - Then call the following endpoint: |
| |
| .... |
| curl -XPOST http://ip:port/servers?reload-certificate |
| .... |
| |
| Optional query parameters: |
| |
| - `port`: positive integer (valid port number). Only reload certificates for the specific port. |
| |
| Return code: |
| |
| - 204: the certificate is reloaded |
| - 400: Invalid request. |
| |
| === Disconnecting users |
| |
| James maintains a set of stateful connections and provide an API allowing to close any of the existing |
| connections, including: |
| |
| - IMAP protocol |
| - SMTP protocol |
| - JMAP websocket and event source sub protocols |
| |
| James keeps track of active channels and would iterate through them, destroying corresponding channels. |
| |
| ==== Disconnecting a specific user |
| |
| .... |
| curl -XDELETE /servers/channels/bob@domain.tld |
| .... |
| |
| Will destroy channels belonging to `bob@domain.tld`. |
| |
| Return code: |
| |
| - 204: disconnect the user successfully |
| |
| ==== Disconnecting all users |
| |
| .... |
| curl -XDELETE /servers/channels |
| .... |
| |
| Will close all channels. |
| |
| Return code: |
| |
| - 204: disconnect all users successfully |
| |
| ==== Disconnecting a group of users |
| |
| .... |
| curl -XDELETE /servers/channels -d `["badGuy1@domain.tld","badGuy1@domain.tld"]` |
| .... |
| |
| Will disconnect `badGuy1@domain.tld` and `badGuy2@domain.tld`. |
| |
| Return code: |
| |
| - 204: disconnect the users successfully |
| - 400: Invalid request |
| |
| === Listing connected users |
| |
| .... |
| curl --XGET /servers/connectedUsers |
| .... |
| |
| Will return a list of users having channels opened on the server: |
| |
| .... |
| [ |
| "alice@domain.tld", |
| "bob@domain.tld" |
| ] |
| .... |
| |
| === Listing channels of a user |
| |
| .... |
| curl -XGET /servers/channels/bob@domain |
| .... |
| |
| Will return a description and statistics for channels of a user: |
| |
| .... |
| [ |
| { |
| "protocol": "IMAP", |
| "endpoint": "imapserver", |
| "remoteAddress": "127.0.0.1", |
| "connectionDate": "2024-11-21T10:46:37.476425406Z", |
| "isActive": true, |
| "isOpen": true, |
| "isWritable": true, |
| "isEncrypted": false, |
| "username": "bob@domain", |
| "protocolSpecificInformation": { |
| "loggedInUser": "bob@domain", |
| "isCompressed": "false", |
| "selectedMailbox": "1", |
| "isIdling": "false", |
| "requestCount": "3", |
| "userAgent": "{name=Thunderbird, version=102.7.1}", |
| "cumulativeWrittenBytes": "448", |
| "cumulativeReadBytes": "103", |
| "liveReadThroughputBytePerSecond": "0", |
| "liveWriteThroughputBytePerSecond": "0" |
| } |
| } |
| ] |
| .... |
| |
| |
| === Listing all channels |
| |
| .... |
| curl -XGET /servers/channels |
| .... |
| |
| Will return a description and statistics for channels of all users: |
| |
| .... |
| [ |
| { |
| "protocol": "IMAP", |
| "endpoint": "imapserver", |
| "remoteAddress": "127.0.0.1", |
| "connectionDate": "2024-11-21T10:46:37.476425406Z", |
| "isActive": true, |
| "isOpen": true, |
| "isWritable": true, |
| "isEncrypted": false, |
| "username": "bob@domain", |
| "protocolSpecificInformation": { |
| "loggedInUser": "bob@domain", |
| "isCompressed": "false", |
| "selectedMailbox": "1", |
| "isIdling": "false", |
| "requestCount": "3", |
| "userAgent": "{name=Thunderbird, version=102.7.1}", |
| "cumulativeWrittenBytes": "448", |
| "cumulativeReadBytes": "103", |
| "liveReadThroughputBytePerSecond": "0", |
| "liveWriteThroughputBytePerSecond": "0" |
| } |
| } |
| ] |
| .... |
| |
| Be warned that the output can be very large if a significant count of channels is opened. |