| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <title>Distributed James Server — WebAdmin REST administration API :: Apache James</title> |
| <meta name="generator" content="Antora 3.1.2"> |
| <link rel="stylesheet" href="../../../_/css/site.css"> |
| </head> |
| <body class="article"> |
| <header class="header"> |
| <nav class="navbar"> |
| <div class="navbar-brand"> |
| <a class="navbar-item" href="https://james.apache.org"><img src="/_/img/james.svg" alt="james logo"> Apache James</a> |
| <button class="navbar-burger" data-target="topbar-nav"> |
| <span></span> |
| <span></span> |
| <span></span> |
| </button> |
| </div> |
| <div id="topbar-nav" class="navbar-menu"> |
| <div class="navbar-end"> |
| <a class="navbar-item" href="#">Home</a> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Products</a> |
| <div class="navbar-dropdown"> |
| <div class="navbar-item"><strong>James server</strong></div> |
| <a class="navbar-item" href="https://github.com/apache/james-project">Repository</a> |
| <a class="navbar-item" href="https://issues.apache.org/jira/projects/JAMES/issues">Issue Tracker</a> |
| <hr class="navbar-divider"> |
| <a class="navbar-item" href="https://james.apache.org/mime4j/index.html">Mime4J</a> |
| <a class="navbar-item" href="https://james.apache.org/jsieve/index.html">jSieve</a> |
| <a class="navbar-item" href="https://james.apache.org/jspf/index.html">jSPF</a> |
| <a class="navbar-item" href="https://james.apache.org/jdkim/index.html">jDKIM</a> |
| <a class="navbar-item" href="https://james.apache.org/hupa/index.html">HUPA</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Community</a> |
| <div class="navbar-dropdown"> |
| <!-- Not ideal but dropping the version in the href requires tweaking james-projet docs module first --> |
| <a class="navbar-item" href="/james-project/3.6.0/community/mailing-lists.html">Mailing lists</a> |
| <a class="navbar-item" href="https://gitter.im/apache/james-project"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" class="logo-gitter-sign" data-v-44ebcb1a=""><rect x="15" y="5" width="2" height="10"></rect> <rect x="10" y="5" width="2" height="20"></rect> <rect x="5" y="5" width="2" height="20"></rect> <rect width="2" height="15"></rect></svg> Gitter</a> |
| <a class="navbar-item" href="https://twitter.com/ApacheJames"> |
| <span class="icon"> |
| <svg aria-hidden="true" data-icon="twitter" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> |
| <path fill="#57aaee" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path> |
| </svg> |
| </span> Twitter |
| </a> |
| <a class="navbar-item" href="#"> <svg class="octicon octicon-mark-github v-align-middle" viewBox="0 0 16 16" version="1.1" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg> Github</a> |
| </div> |
| </div> |
| <!-- <div class="navbar-item"> |
| <span class="control"> |
| <a class="button is-primary" href="#">Download</a> |
| </span> |
| </div> --> |
| </div> |
| </div> |
| </nav> |
| </header> |
| <div class="body"> |
| <div class="nav-container" data-component="james-distributed-app" data-version="3.8.0"> |
| <aside class="nav"> |
| <div class="panels"> |
| <div class="nav-panel-menu is-active" data-panel="menu"> |
| <nav class="nav-menu"> |
| <button class="nav-menu-toggle" aria-label="Toggle expand/collapse all" style="display: none"></button> |
| <h3 class="title"><a href="../index.html">Apache James Distributed Server</a></h3> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../index.html">Distributed James Application</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../objectives.html">Objectives and motivation</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../architecture/index.html">Architecture</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../architecture/implemented-standards.html">Implemented standards</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../architecture/consistency-model.html">Consistency Model</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../architecture/specialized-instances.html">Specialized instances</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../run/index.html">Run</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../run/run-java.html">Run with Java</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../run/run-docker.html">Run with Docker</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../run/run-kubernetes.html">Run with Kubernetes</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../run/k8s-checklist.html">Deployment Checklist</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../run/k8s-logsMetrics.html">Logs & Metrics</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../run/k8s-values.html">values.yaml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../run/k8s-secrets.html">secrets.yaml</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../configure/index.html">Configuration</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Protocols</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/imap.html">imapserver.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/jmap.html">jmap.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/jmx.html">jmx.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/smtp.html">smtpserver.xml & lmtpserver.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/smtp-hooks.html">Packaged SMTP hooks</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/pop3.html">pop3server.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/webadmin.html">webadmin.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/ssl.html">SSL & TLS</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/sieve.html">Sieve & ManageSieve</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Storage dependencies</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/blobstore.html">blobstore.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/cassandra.html">cassandra.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/opensearch.html">opensearch.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/rabbitmq.html">rabbitmq.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/redis.html">redis.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/tika.html">tika.properties</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Core components</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/batchsizes.html">batchsizes.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/dns.html">dnsservice.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/domainlist.html">domainlist.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/healthcheck.html">healthcheck.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/mailetcontainer.html">mailetcontainer.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/mailets.html">Packaged Mailets</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/matchers.html">Packaged Matchers</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/mailrepositorystore.html">mailrepositorystore.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/recipientrewritetable.html">recipientrewritetable.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/search.html">search.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/usersrepository.html">usersrepository.xml</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Extensions</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/vault.html">deletedMessageVault.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/extensions.html">extensions.properties</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/listeners.html">listeners.xml</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/spam.html">Anti-Spam setup</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/remote-delivery-error-handling.html">About RemoteDelivery error handling</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/collecting-contacts.html">Contact collection</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/collecting-events.html">Event collection</a> |
| </li> |
| <li class="nav-item" data-depth="4"> |
| <a class="nav-link" href="../configure/dsn.html">ESMTP DSN support</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="index.html">Operate</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="guide.html">Operator guide</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="performanceChecklist.html">Performance checklist</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="logging.html">Logging</a> |
| </li> |
| <li class="nav-item is-current-page" data-depth="3"> |
| <a class="nav-link" href="webadmin.html">WebAdmin REST administration API</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="metrics.html">Metrics</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="migrating.html">Migrating existing data</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="cli.html">Command Line Interface</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="cassandra-migration.html">Cassandra migration</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="security.html">Security checklist</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../extending/index.html">Extending server behavior</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../extending/mail-processing.html">Custom mail processing components</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../extending/mailbox-listeners.html">Custom Mailbox Listeners</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../extending/smtp-hooks.html">Custom SMTP hooks</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../extending/webadmin-routes.html">Custom WebAdmin routes</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../extending/imap.html">Custom IMAP processing</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <a class="nav-link" href="../benchmark/index.html">Performance benchmark</a> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../benchmark/db-benchmark.html">Database benchmarks</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../benchmark/james-benchmark.html">James benchmarks</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </nav> |
| </div> |
| <div class="nav-panel-explore" data-panel="explore"> |
| <div class="context"> |
| <span class="title">Apache James Distributed Server</span> |
| <span class="version">3.8.0 SNAPSHOT</span> |
| </div> |
| <ul class="components"> |
| <li class="component is-current"> |
| <div class="title"><a href="../index.html">Apache James Distributed Server</a></div> |
| <ul class="versions"> |
| <li class="version is-current is-latest"> |
| <a href="../index.html">3.8.0 SNAPSHOT</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <div class="title"><a href="../../../james-project/3.8.0/index.html">Apache James Server</a></div> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../james-project/3.8.0/index.html">3.8.0 SNAPSHOT</a> |
| </li> |
| <li class="version"> |
| <a href="../../../james-project/3.6.0/index.html">3.6.0 Snapshot</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <div class="title"><a href="../../../james-site/latest/index.html">Apache James Site</a></div> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../james-site/latest/index.html">latest</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </aside> |
| </div> |
| <main class="article"> |
| <div class="toolbar" role="navigation"> |
| <button class="nav-toggle"></button> |
| <a href="../../../james-site/latest/homepage.html" class="home-link"></a> |
| <nav class="breadcrumbs" aria-label="breadcrumbs"> |
| <ul> |
| <li><a href="../index.html">Apache James Distributed Server</a></li> |
| <li><a href="../index.html">Distributed James Application</a></li> |
| <li><a href="index.html">Operate</a></li> |
| <li><a href="webadmin.html">WebAdmin REST administration API</a></li> |
| </ul> |
| </nav> |
| <div class="edit-this-page"><a href="https://github.com/apache/james-project/blob/master/server/apps/distributed-app/docs/modules/ROOT/pages/operate/webadmin.adoc">Edit this Page</a></div> |
| </div> |
| <div class="content"> |
| <aside class="toc sidebar" data-title="Contents" data-levels="2"> |
| <div class="toc-menu"></div> |
| </aside> |
| <article class="doc"> |
| <h1 class="page">Distributed James Server — WebAdmin REST administration API</h1> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The web administration supports for now the CRUD operations on the domains, the users, their mailboxes and their quotas, |
| managing mail repositories, performing cassandra migrations, and much more, as described in the following sections.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>WARNING</strong>: 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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In case of any error, the system will return an error message which is |
| json format like this:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| statusCode: <error_code>, |
| type: <error_type>, |
| message: <the_error_message> |
| cause: <the_detail_message_from_throwable> |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Finally, please note that in case of a malformed URL the 400 bad request |
| response will contain an HTML body.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_healthcheck"><a class="anchor" href="#_healthcheck"></a>HealthCheck</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_check_all_components"><a class="anchor" href="#_check_all_components"></a>Check all components</h3> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/healthcheck</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return a list of healthChecks execution result, with an aggregated |
| result:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "status": "healthy", |
| "checks": [ |
| { |
| "componentName": "Cassandra backend", |
| "escapedComponentName": "Cassandra%20backend", |
| "status": "healthy" |
| "cause": null |
| } |
| ] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>status</strong> field can be:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>healthy</strong>: Component works normally</p> |
| </li> |
| <li> |
| <p><strong>degraded</strong>: Component works in degraded mode. Some non-critical |
| services may not be working, or latencies are high, for example. Cause |
| contains explanations.</p> |
| </li> |
| <li> |
| <p><strong>unhealthy</strong>: The component is currently not working. Cause contains |
| explanations.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Supported health checks include:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>Cassandra backend</strong>: Cassandra storage.</p> |
| </li> |
| <li> |
| <p><strong>OpenSearch Backend</strong>: OpenSearch storage.</p> |
| </li> |
| <li> |
| <p><strong>EventDeadLettersHealthCheck</strong></p> |
| </li> |
| <li> |
| <p><strong>Guice application lifecycle</strong></p> |
| </li> |
| <li> |
| <p><strong>JPA Backend</strong>: JPA storage.</p> |
| </li> |
| <li> |
| <p><strong>MailReceptionCheck</strong> 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.</p> |
| </li> |
| <li> |
| <p><strong>MessageFastViewProjection</strong> 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 <code>degraded</code>)</p> |
| </li> |
| <li> |
| <p><strong>RabbitMQ backend</strong>: RabbitMQ messaging.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: All checks have answered with a Healthy or Degraded status. James |
| services can still be used.</p> |
| </li> |
| <li> |
| <p>503: At least one check have answered with a Unhealthy status</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_check_single_component"><a class="anchor" href="#_check_single_component"></a>Check single component</h3> |
| <div class="paragraph"> |
| <p>Performs a health check for the given component. The component is |
| referenced by its URL encoded name.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/healthcheck/checks/Cassandra%20backend</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the component’s name, the component’s escaped name, the |
| health status and a cause.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "componentName": "Cassandra backend", |
| "escapedComponentName": "Cassandra%20backend", |
| "status": "healthy" |
| "cause": null |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The check has answered with a Healthy or Degraded status.</p> |
| </li> |
| <li> |
| <p>404: A component with the given name was not found.</p> |
| </li> |
| <li> |
| <p>503: The check has answered with an Unhealthy status.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_list_all_health_checks"><a class="anchor" href="#_list_all_health_checks"></a>List all health checks</h3> |
| <div class="paragraph"> |
| <p>This endpoint lists all the available health checks.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/healthcheck/checks</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the list of all available health checks.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| { |
| "componentName": "Cassandra backend", |
| "escapedComponentName": "Cassandra%20backend" |
| } |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: List of available health checks</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_task_management"><a class="anchor" href="#_task_management"></a>Task management</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Some webadmin features schedule tasks. The task management API allow to |
| monitor and manage the execution of the following tasks.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the <code>taskId</code> used in the following APIs is returned by other |
| WebAdmin APIs scheduling tasks.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_getting_a_task_details"><a class="anchor" href="#_getting_a_task_details"></a>Getting a task details</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>An Execution Report will be returned:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>status</code> can have the value:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>waiting</code>: The task is scheduled but its execution did not start yet</p> |
| </li> |
| <li> |
| <p><code>inProgress</code>: The task is currently executed</p> |
| </li> |
| <li> |
| <p><code>cancelled</code>: The task had been cancelled</p> |
| </li> |
| <li> |
| <p><code>completed</code>: The task execution is finished, and this execution is a |
| success</p> |
| </li> |
| <li> |
| <p><code>failed</code>: The task execution is finished, and this execution is a |
| failure</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p><code>additionalInformation</code> is a task specific object giving additional |
| information and context about that task. The structure of this |
| <code>additionalInformation</code> field is provided along the specific task |
| submission endpoint.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The specific task was found and the execution report exposed |
| above is returned</p> |
| </li> |
| <li> |
| <p>400: Invalid task ID</p> |
| </li> |
| <li> |
| <p>404: Task ID was not found</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_awaiting_a_task"><a class="anchor" href="#_awaiting_a_task"></a>Awaiting a task</h3> |
| <div class="paragraph"> |
| <p>One can await the end of a task, then receive its final execution |
| report.</p> |
| </div> |
| <div class="paragraph"> |
| <p>That feature is especially usefully for testing purpose but still can |
| serve real-life scenario.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2/await?timeout=duration</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>An Execution Report will be returned.</p> |
| </div> |
| <div class="paragraph"> |
| <p><code>timeout</code> is optional. By default it is set to 365 days (the maximum |
| value). The expected value is expressed in the following format: |
| <code>Nunit</code>. <code>N</code> should be strictly positive. <code>unit</code> could be either in the |
| short form (<code>s</code>, <code>m</code>, <code>h</code>, etc.), or in the long form (<code>day</code>, <code>week</code>, |
| <code>month</code>, etc.).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Examples:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>30s</code></p> |
| </li> |
| <li> |
| <p><code>5m</code></p> |
| </li> |
| <li> |
| <p><code>7d</code></p> |
| </li> |
| <li> |
| <p><code>1y</code></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The specific task was found and the execution report exposed |
| above is returned</p> |
| </li> |
| <li> |
| <p>400: Invalid task ID or invalid timeout</p> |
| </li> |
| <li> |
| <p>404: Task ID was not found</p> |
| </li> |
| <li> |
| <p>408: The timeout has been reached</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_cancelling_a_task"><a class="anchor" href="#_cancelling_a_task"></a>Cancelling a task</h3> |
| <div class="paragraph"> |
| <p>You can cancel a task by calling:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Task had been cancelled</p> |
| </li> |
| <li> |
| <p>400: Invalid task ID</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_tasks"><a class="anchor" href="#_listing_tasks"></a>Listing tasks</h3> |
| <div class="paragraph"> |
| <p>A list of all tasks can be retrieved:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/tasks</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return a list of Execution reports</p> |
| </div> |
| <div class="paragraph"> |
| <p>One can filter the above results by status. For example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/tasks?status=inProgress</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return a list of Execution reports that are currently in progress. This list is sorted by |
| reverse submitted date (recent tasks goes first).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: A list of corresponding tasks is returned</p> |
| </li> |
| <li> |
| <p>400: Invalid status value</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Additional optional task parameters are supported:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>status</code> one of <code>waiting</code>, <code>inProgress</code>, <code>canceledRequested</code>, <code>completed</code>, <code>canceled</code>, <code>failed</code>. Only |
| tasks with the given status are returned.</p> |
| </li> |
| <li> |
| <p><code>type</code>: only tasks with the given type are returned.</p> |
| </li> |
| <li> |
| <p><code>submittedBefore</code>: Date. Returns only tasks submitted before this date.</p> |
| </li> |
| <li> |
| <p><code>submittedAfter</code>: Date. Returns only tasks submitted after this date.</p> |
| </li> |
| <li> |
| <p><code>startedBefore</code>: Date. Returns only tasks started before this date.</p> |
| </li> |
| <li> |
| <p><code>startedAfter</code>: Date. Returns only tasks started after this date.</p> |
| </li> |
| <li> |
| <p><code>completedBefore</code>: Date. Returns only tasks completed before this date.</p> |
| </li> |
| <li> |
| <p><code>completedAfter</code>: Date. Returns only tasks completed after this date.</p> |
| </li> |
| <li> |
| <p><code>failedBefore</code>: Date. Returns only tasks failed before this date.</p> |
| </li> |
| <li> |
| <p><code>failedAfter</code>: Date. Returns only tasks faield after this date.</p> |
| </li> |
| <li> |
| <p><code>offset</code>: Integer, number of tasks to skip in the response. Useful for paging.</p> |
| </li> |
| <li> |
| <p><code>limit</code>: Integer, maximum number of tasks to return in one call</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Example of date format: <code>2023-04-15T07:23:27.541254+07:00</code> and <code>2023-04-15T07%3A23%3A27.541254%2B07%3A00</code> once URL encoded.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_endpoints_returning_a_task"><a class="anchor" href="#_endpoints_returning_a_task"></a>Endpoints returning a task</h3> |
| <div class="paragraph"> |
| <p>Many endpoints do generate a task.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /endpoint?action={action}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The response to these requests will be the scheduled <code>taskId</code> :</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"taskId":"5641376-02ed-47bd-bcc7-76ff6262d92a"}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Positionned headers:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Location header indicates the location of the resource associated with |
| the scheduled task. Example:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>Location: /tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>Other response codes might be returned depending on the endpoint</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The additional information returned depends on the scheduled task type |
| and is documented in the endpoint documentation.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_domains"><a class="anchor" href="#_administrating_domains"></a>Administrating domains</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_create_a_domain"><a class="anchor" href="#_create_a_domain"></a>Create a domain</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/domains/domainToBeCreated</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name domainToBeCreated:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>can not be null or empty</p> |
| </li> |
| <li> |
| <p>can not contain `@'</p> |
| </li> |
| <li> |
| <p>can not be more than 255 characters</p> |
| </li> |
| <li> |
| <p>can not contain `/'</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The domain was successfully added</p> |
| </li> |
| <li> |
| <p>400: The domain name is invalid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_delete_a_domain"><a class="anchor" href="#_delete_a_domain"></a>Delete a domain</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/domains/{domainToBeDeleted}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>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 <a href="https://james.apache.org/server/config-domainlist.html">domain list |
| configuration</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The domain was successfully removed</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_test_if_a_domain_exists"><a class="anchor" href="#_test_if_a_domain_exists"></a>Test if a domain exists</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/domains/{domainName}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The domain exists</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_get_the_list_of_domains"><a class="anchor" href="#_get_the_list_of_domains"></a>Get the list of domains</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/domains</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Possible response:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["domain1", "domain2"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The domain list was successfully retrieved</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_get_the_list_of_aliases_for_a_domain"><a class="anchor" href="#_get_the_list_of_aliases_for_a_domain"></a>Get the list of aliases for a domain</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/domains/destination.domain.tld/aliases</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Possible response:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| {"source": "source1.domain.tld"}, |
| {"source": "source2.domain.tld"} |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When sending an email to an email address having <code>source1.domain.tld</code> or |
| <code>source2.domain.tld</code> as a domain part (example: |
| <code>user@source1.domain.tld</code>), then the domain part will be rewritten into |
| destination.domain.tld (so into <code>user@destination.domain.tld</code>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The domain aliases was successfully retrieved</p> |
| </li> |
| <li> |
| <p>400: destination.domain.tld has an invalid syntax</p> |
| </li> |
| <li> |
| <p>404: destination.domain.tld is not part of handled domains and does |
| not have local domains as aliases.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_create_an_alias_for_a_domain"><a class="anchor" href="#_create_an_alias_for_a_domain"></a>Create an alias for a domain</h3> |
| <div class="paragraph"> |
| <p>To create a domain alias execute the following query:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/domains/destination.domain.tld/aliases/source.domain.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When sending an email to an email address having <code>source.domain.tld</code> as |
| a domain part (example: <code>user@source.domain.tld</code>), then the domain part |
| will be rewritten into <code>destination.domain.tld</code> (so into |
| <code>user@destination.domain.tld</code>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The redirection now exists</p> |
| </li> |
| <li> |
| <p>400: <code>source.domain.tld</code> or <code>destination.domain.tld</code> have an invalid |
| syntax</p> |
| </li> |
| <li> |
| <p>400: <code>source, domain</code> and <code>destination domain</code> are the same</p> |
| </li> |
| <li> |
| <p>404: <code>source.domain.tld</code> are not part of handled domains.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Be aware that no checks to find possible loops that would result of this creation will be performed.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_delete_an_alias_for_a_domain"><a class="anchor" href="#_delete_an_alias_for_a_domain"></a>Delete an alias for a domain</h3> |
| <div class="paragraph"> |
| <p>To delete a domain alias execute the following query:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/domains/destination.domain.tld/aliases/source.domain.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When sending an email to an email address having <code>source.domain.tld</code> as |
| a domain part (example: <code>user@source.domain.tld</code>), then the domain part |
| will be rewritten into <code>destination.domain.tld</code> (so into |
| <code>user@destination.domain.tld</code>).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The redirection now no longer exists</p> |
| </li> |
| <li> |
| <p>400: <code>source.domain.tld</code> or destination.domain.tld have an invalid |
| syntax</p> |
| </li> |
| <li> |
| <p>400: source, domain and destination domain are the same</p> |
| </li> |
| <li> |
| <p>404: <code>source.domain.tld</code> are not part of handled domains.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_delete_all_users_data_of_a_domain"><a class="anchor" href="#_delete_all_users_data_of_a_domain"></a>Delete all users data of a domain</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/domains/{domainToBeUsed}?action=deleteData</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Would create a task that deletes data of all users of the domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>[More details about endpoints returning a task](#_endpoints_returning_a_task).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>DeleteUsersDataOfDomainTask</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type": "DeleteUsersDataOfDomainTask", |
| "domain": "domain.tld", |
| "successfulUsersCount": 2, |
| "failedUsersCount": 1, |
| "failedUsers": ["faileduser@domain.tld"], |
| "timestamp": "2023-05-22T08:52:47.076261Z" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Notes: <code>failedUsers</code> only lists maximum 100 failed users.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_users"><a class="anchor" href="#_administrating_users"></a>Administrating users</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_create_a_user"><a class="anchor" href="#_create_a_user"></a>Create a user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/users/usernameToBeUsed \ |
| -d '{"password":"passwordToBeUsed"}' \ |
| -H "Content-Type: application/json"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name usernameToBeUsed representing valid users, hence it should |
| match the criteria at <a href="../configure/usersrepository.html" class="xref page">User Repositories documentation</a></p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The user was successfully created</p> |
| </li> |
| <li> |
| <p>400: The user name or the payload is invalid</p> |
| </li> |
| <li> |
| <p>409: The user name already exists</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>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 <strong>Update a user password</strong> below.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_updating_a_user_password"><a class="anchor" href="#_updating_a_user_password"></a>Updating a user password</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/users/usernameToBeUsed?force \ |
| -d '{"password":"passwordToBeUsed"}' \ |
| -H "Content-Type: application/json"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The user’s password was successfully updated</p> |
| </li> |
| <li> |
| <p>400: The user name or the payload is invalid</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This also can be used to create a new user.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_verifying_a_user_password"><a class="anchor" href="#_verifying_a_user_password"></a>Verifying a user password</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/usernameToBeUsed/verify \ |
| -d '{"password":"passwordToBeVerified"}' \ |
| -H "Content-Type: application/json"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The user’s password was correct</p> |
| </li> |
| <li> |
| <p>401: Wrong password or user does not exist</p> |
| </li> |
| <li> |
| <p>400: The user name or the payload is invalid</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This intentionally treats non-existing users as unauthenticated, to prevent a username oracle attack.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_testing_a_user_existence"><a class="anchor" href="#_testing_a_user_existence"></a>Testing a user existence</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XHEAD http://ip:port/users/usernameToBeUsed</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name ``usernameToBeUsed'' represents a valid user, hence it |
| should match the criteria at <a href="../configure/usersrepository.html" class="xref page">User Repositories documentation</a></p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The user exists</p> |
| </li> |
| <li> |
| <p>400: The user name is invalid</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_a_user"><a class="anchor" href="#_deleting_a_user"></a>Deleting a user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/{userToBeDeleted}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The user was successfully deleted</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_retrieving_the_user_list"><a class="anchor" href="#_retrieving_the_user_list"></a>Retrieving the user list</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[{"username":"username@domain-jmapauthentication.tld"},{"username":"username@domain.tld"}]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The user name list was successfully retrieved</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_retrieving_the_list_of_allowed_from_headers_for_a_given_user"><a class="anchor" href="#_retrieving_the_list_of_allowed_from_headers_for_a_given_user"></a>Retrieving the list of allowed <code>From</code> headers for a given user</h3> |
| <div class="paragraph"> |
| <p>This endpoint allows to know which From headers a given user is allowed to use when sending mails.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/givenUser/allowedFromHeaders</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["user@domain.tld","alias@domain.tld"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The list was successfully retrieved</p> |
| </li> |
| <li> |
| <p>400: The user is invalid</p> |
| </li> |
| <li> |
| <p>404: The user is unknown</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_add_a_delegated_user_of_a_base_user"><a class="anchor" href="#_add_a_delegated_user_of_a_base_user"></a>Add a delegated user of a base user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/users/baseUser/authorizedUsers/delegatedUser</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Addition of the delegated user succeeded</p> |
| </li> |
| <li> |
| <p>404: The base user does not exist</p> |
| </li> |
| <li> |
| <p>400: The delegated user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note: Delegation is only available on top of Cassandra products and not implemented yet on top of JPA backends.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_remove_a_delegated_user_of_a_base_user"><a class="anchor" href="#_remove_a_delegated_user_of_a_base_user"></a>Remove a delegated user of a base user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/baseUser/authorizedUsers/delegatedUser</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Removal of the delegated user succeeded</p> |
| </li> |
| <li> |
| <p>404: The base user does not exist</p> |
| </li> |
| <li> |
| <p>400: The delegated user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note: Delegation is only available on top of Cassandra products and not implemented yet on top of JPA backends.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_retrieving_the_list_of_delegated_users_of_a_base_user"><a class="anchor" href="#_retrieving_the_list_of_delegated_users_of_a_base_user"></a>Retrieving the list of delegated users of a base user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/baseUser/authorizedUsers</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["alice@domain.tld","bob@domain.tld"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The list was successfully retrieved</p> |
| </li> |
| <li> |
| <p>404: The base user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note: Delegation is only available on top of Cassandra products and not implemented yet on top of JPA backends.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_remove_all_delegated_users_of_a_base_user"><a class="anchor" href="#_remove_all_delegated_users_of_a_base_user"></a>Remove all delegated users of a base user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/baseUser/authorizedUsers</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Removal of the delegated users succeeded</p> |
| </li> |
| <li> |
| <p>404: The base user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note: Delegation is only available on top of Cassandra products and not implemented yet on top of JPA backends.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_change_a_username"><a class="anchor" href="#_change_a_username"></a>Change a username</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/oldUser/rename/newUser?action=rename</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Would migrate account data from <code>oldUser</code> to <code>newUser</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Implemented migration steps are:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>ForwardUsernameChangeTaskStep</code>: creates forward from old user to new user and migrates existing forwards</p> |
| </li> |
| <li> |
| <p><code>FilterUsernameChangeTaskStep</code>: migrates users filtering rules</p> |
| </li> |
| <li> |
| <p><code>DelegationUsernameChangeTaskStep</code>: migrates delegations where the impacted user is either delegatee or delegator</p> |
| </li> |
| <li> |
| <p><code>MailboxUsernameChangeTaskStep</code>: migrates mailboxes belonging to the old user to the account of the new user. It also |
| migrates user’s mailbox subscriptions.</p> |
| </li> |
| <li> |
| <p><code>ACLUsernameChangeTaskStep</code>: migrates ACLs on mailboxes the migrated user has access to and updates subscriptions accordingly.</p> |
| </li> |
| <li> |
| <p><code>QuotaUsernameChangeTaskStep</code>: migrates quotas user from old user to new user.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>fromStep</code> query parameter allows skipping previous steps, allowing to resume the username change from a failed step.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>UsernameChangeTask</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Valid status includes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>SKIPPED</code>: bypassed via <code>fromStep</code> setting</p> |
| </li> |
| <li> |
| <p><code>WAITING</code>: Awaits execution</p> |
| </li> |
| <li> |
| <p><code>IN_PROGRESS</code>: Currently executed</p> |
| </li> |
| <li> |
| <p><code>FAILED</code>: Error encountered while executing this step. Check the logs.</p> |
| </li> |
| <li> |
| <p><code>ABORTED</code>: Won’t be executed because of previous step failures.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_delete_data_of_a_user"><a class="anchor" href="#_delete_data_of_a_user"></a>Delete data of a user</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/usernameToBeUsed?action=deleteData</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Would create a task that deletes data of the user.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Implemented deletion steps are:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>RecipientRewriteTableUserDeletionTaskStep</code>: deletes all rewriting rules related to this user.</p> |
| </li> |
| <li> |
| <p><code>FilterUserDeletionTaskStep</code>: deletes all filters belonging to the user.</p> |
| </li> |
| <li> |
| <p><code>DelegationUserDeletionTaskStep</code>: deletes all delegations from / to the user.</p> |
| </li> |
| <li> |
| <p><code>MailboxUserDeletionTaskStep</code>: deletes mailboxes of this user, all ACLs of this user, as well as his subscriptions.</p> |
| </li> |
| <li> |
| <p><code>WebPushUserDeletionTaskStep</code>: deletes push data registered for this user.</p> |
| </li> |
| <li> |
| <p><code>IdentityUserDeletionTaskStep</code>: deletes identities registered for this user.</p> |
| </li> |
| <li> |
| <p><code>VacationUserDeletionTaskStep</code>: deletes vacations registered for this user.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>fromStep</code> query parameter allows skipping previous steps, allowing to resume the user data deletion from a failed step.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>DeleteUserDataTask</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type": "DeleteUserDataTask", |
| "username": "jessy.jones@domain.tld", |
| "status": { |
| "A": "DONE", |
| "B": "FAILED", |
| "C": "ABORTED" |
| }, |
| "fromStep": null, |
| "timestamp": "2023-02-17T02:54:01.246477Z" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Valid status includes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>SKIPPED</code>: bypassed via <code>fromStep</code> setting</p> |
| </li> |
| <li> |
| <p><code>WAITING</code>: Awaits execution</p> |
| </li> |
| <li> |
| <p><code>IN_PROGRESS</code>: Currently executed</p> |
| </li> |
| <li> |
| <p><code>FAILED</code>: Error encountered while executing this step. Check the logs.</p> |
| </li> |
| <li> |
| <p><code>ABORTED</code>: Won’t be executed because of previous step failures.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_retrieving_the_user_identities"><a class="anchor" href="#_retrieving_the_user_identities"></a>Retrieving the user identities</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/{baseUser}/identities?default=true</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>API to get the list of identities of a user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The response will look like:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-none hljs">[ |
| { |
| "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" |
| } |
| ] |
| } |
| ]</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Query parameters:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>default: (Optional) allows getting the default identity of a user. In order to do that: <code>default=true</code></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The list was successfully retrieved</p> |
| </li> |
| <li> |
| <p>400: The user is invalid</p> |
| </li> |
| <li> |
| <p>404: The user is unknown or the default identity can not be found.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The optional <code>default</code> query parameter allows getting the default identity of a user. |
| In order to do that: <code>default=true</code></p> |
| </div> |
| <div class="paragraph"> |
| <p>The web-admin server will return <code>404</code> response code when the default identity can not be found.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_creating_a_jmap_user_identity"><a class="anchor" href="#_creating_a_jmap_user_identity"></a>Creating a JMAP user identity</h3> |
| <div class="paragraph"> |
| <p>API to create a new JMAP user identity</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>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"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: The new identity was successfully created</p> |
| </li> |
| <li> |
| <p>404: The username is unknown</p> |
| </li> |
| <li> |
| <p>400: The payload is invalid</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name ``username'' represents a valid user</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_updating_a_jmap_user_identity"><a class="anchor" href="#_updating_a_jmap_user_identity"></a>Updating a JMAP user identity</h3> |
| <div class="paragraph"> |
| <p>API to update an exist JMAP user identity</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>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"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The identity were successfully updated</p> |
| </li> |
| <li> |
| <p>404: The username is unknown</p> |
| </li> |
| <li> |
| <p>400: The payload is invalid</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>username'' represents a valid user |
| Resource name </code>identityId'' represents a exist user identity</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_vacation_settings"><a class="anchor" href="#_administrating_vacation_settings"></a>Administrating vacation settings</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_get_vacation_settings"><a class="anchor" href="#_get_vacation_settings"></a>Get vacation settings</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/vacation/usernameToBeUsed</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name usernameToBeUsed representing valid users, hence it should |
| match the criteria at <a href="../configure/usersrepository.html" class="xref page">User Repositories documentation</a></p> |
| </div> |
| <div class="paragraph"> |
| <p>The response will look like this:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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>" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The vacation settings were successfully retrieved</p> |
| </li> |
| <li> |
| <p>404: The user name is unknown</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_update_vacation_settings"><a class="anchor" href="#_update_vacation_settings"></a>Update vacation settings</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/vacation/usernameToBeUsed</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Request body must be a JSON structure as described above.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If any field is not set in the request, the corresponding field in the existing vacation message is left unchanged.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The vacation settings were successfully updated</p> |
| </li> |
| <li> |
| <p>404: The user name is unknown</p> |
| </li> |
| <li> |
| <p>400: The payload is invalid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_delete_vacation_settings"><a class="anchor" href="#_delete_vacation_settings"></a>Delete vacation settings</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/vacation/usernameToBeUsed</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For convenience, this disables and clears the existing vacation settings of the user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The vacation settings were successfully disabled</p> |
| </li> |
| <li> |
| <p>404: The user name is unknown</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_mailboxes"><a class="anchor" href="#_administrating_mailboxes"></a>Administrating mailboxes</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_all_mailboxes"><a class="anchor" href="#_all_mailboxes"></a>All mailboxes</h3> |
| <div class="paragraph"> |
| <p>Several actions can be performed on the server mailboxes.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Request pattern is:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?action={action1},...</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The kind of task scheduled depends on the action parameter. See below |
| for details.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_fixing_mailboxes_inconsistencies"><a class="anchor" href="#_fixing_mailboxes_inconsistencies"></a>Fixing mailboxes inconsistencies</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=SolveInconsistencies</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for fixing inconsistencies for the mailbox |
| deduplicated object stored in Cassandra.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>I-KNOW-WHAT-I-M-DOING</code> header is mandatory (you can read more |
| information about it in the warning section below).</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>solve-mailbox-inconsistencies</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"solve-mailbox-inconsistencies", |
| "processedMailboxEntries": 3, |
| "processedMailboxPathEntries": 3, |
| "fixedInconsistencies": 2, |
| "errors": 1, |
| "conflictingEntries":[{ |
| "mailboxDaoEntry":{ |
| "mailboxPath":"#private:user:mailboxName", |
| "mailboxId":"464765a0-e4e7-11e4-aba4-710c1de3782b" |
| }," + |
| "mailboxPathDaoEntry":{ |
| "mailboxPath":"#private:user:mailboxName2", |
| "mailboxId":"464765a0-e4e7-11e4-aba4-710c1de3782b" |
| } |
| }] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that conflicting entry inconsistencies will not be fixed and will |
| require to explicitly use <a href="#_correcting_ghost_mailbox">ghost mailbox</a> |
| endpoint in order to merge the conflicting mailboxes and prevent any |
| message loss.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>WARNING</strong>: this task can cancel concurrently running legitimate user |
| operations upon dirty read. As such this task should be run offline.</p> |
| </div> |
| <div class="paragraph"> |
| <p>A dirty read is when data is read between the two writes of the |
| denormalization operations (no isolation).</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to ensure being offline, stop the traffic on SMTP, JMAP and |
| IMAP ports, for example via re-configuration or firewall rules.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Due to all of those risks, a <code>I-KNOW-WHAT-I-M-DOING</code> header should be |
| positioned to <code>ALL-SERVICES-ARE-OFFLINE</code> in order to prevent accidental |
| calls.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_recomputing_mailbox_counters"><a class="anchor" href="#_recomputing_mailbox_counters"></a>Recomputing mailbox counters</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=RecomputeMailboxCounters</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will recompute counters (unseen & total count) for the mailbox object |
| stored in Cassandra.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Cassandra maintains a per mailbox projection for message count and |
| unseen message count. As with any projection, it can go out of sync, |
| leading to inconsistent results being returned to the client.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>recompute-mailbox-counters</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"recompute-mailbox-counters", |
| "processedMailboxes": 3, |
| "failedMailboxes": ["464765a0-e4e7-11e4-aba4-710c1de3782b"] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that conflicting inconsistencies entries will not be fixed and will |
| require to explicitly use <a href="#_correcting_ghost_mailbox">ghost mailbox</a> |
| endpoint in order to merge the conflicting mailboxes and prevent any |
| message loss.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>WARNING</strong>: this task do not take into account concurrent modifications |
| upon a single mailbox counter recomputation. Rerunning the task will |
| <em>eventually</em> provide the consistent result. As such we advise to run |
| this task offline.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to ensure being offline, stop the traffic on SMTP, JMAP and |
| IMAP ports, for example via re-configuration or firewall rules.</p> |
| </div> |
| <div class="paragraph"> |
| <p><code>trustMessageProjection</code> query parameter can be set to <code>true</code>. Content |
| of <code>messageIdTable</code> (listing messages by their mailbox context) table |
| will be trusted and not compared against content of <code>imapUidTable</code> table |
| (listing messages by their messageId mailbox independent identifier). |
| This will result in a better performance running the task at the cost of |
| safety in the face of message denormalization inconsistencies.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Defaults to false, which generates additional checks. You can read |
| <a href="https://github.com/apache/james-project/blob/master/src/adr/0022-cassandra-message-inconsistency.md">this |
| ADR</a> to better understand the message projection and how it can become |
| inconsistent.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_recomputing_global_jmap_fast_message_view_projection"><a class="anchor" href="#_recomputing_global_jmap_fast_message_view_projection"></a>Recomputing Global JMAP fast message view projection</h4> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These projection items are asynchronously computed on mailbox events.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can force the full projection recomputation by calling the following |
| endpoint:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=recomputeFastViewProjectionItems</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for recomputing the fast message view projection |
| for all mailboxes.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed, per |
| second. Defaults to 10.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=recomputeFastViewProjectionItems&messagesPerSecond=20</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>RecomputeAllFastViewProjectionItemsTask</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"RecomputeAllPreviewsTask", |
| "processedUserCount": 3, |
| "processedMessageCount": 3, |
| "failedUserCount": 2, |
| "failedMessageCount": 1, |
| "runningOptions": { |
| "messagesPerSecond":20 |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_populate_email_query_view"><a class="anchor" href="#_populate_email_query_view"></a>Populate email query view</h4> |
| <div class="paragraph"> |
| <p>Email query view is an optional projection to offload common JMAP <code>Email/query</code> requests used for listing mails on Cassandra |
| and not on the search index thus improving the overall reliability / performance on this operation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These projection items are asynchronously computed on mailbox events.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can populate this projection with the following request:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=populateEmailQueryView</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for recomputing the fast message view projection |
| for all mailboxes.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed, per |
| second. Defaults to 10.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=populateEmailQueryView&messagesPerSecond=20</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>PopulateEmailQueryViewTask</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"PopulateEmailQueryViewTask", |
| "processedUserCount": 3, |
| "processedMessageCount": 3, |
| "failedUserCount": 2, |
| "failedMessageCount": 1, |
| "runningOptions": { |
| "messagesPerSecond":20 |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_recomputing_cassandra_filtering_projection"><a class="anchor" href="#_recomputing_cassandra_filtering_projection"></a>Recomputing Cassandra filtering projection</h4> |
| <div class="paragraph"> |
| <p>You can force the reset of the Cassandra filtering projection by calling the following |
| endpoint:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=populateFilteringProjection</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>PopulateFilteringProjectionTask</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"RecomputeAllPreviewsTask", |
| "processedUserCount": 3, |
| "failedUserCount": 2 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_reindexing_action"><a class="anchor" href="#_reindexing_action"></a>ReIndexing action</h4> |
| <div class="paragraph"> |
| <p>Be also aware of the limits of this API:</p> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: During the re-indexing, the result of search operations might |
| be altered.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: Canceling this task should be considered unsafe as it will |
| leave the currently reIndexed mailbox as partially indexed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="sect4"> |
| <h5 id="_reindexing_all_mails"><a class="anchor" href="#_reindexing_all_mails"></a>ReIndexing all mails</h5> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mailboxes?task=reIndex</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for reIndexing all the mails stored on this James |
| server.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed per |
| second. Default is 50.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can also specify the reindexing mode it wants to use when |
| running the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>mode</code> the reindexing mode used. There are 2 modes for the moment:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>rebuildAll</code> allows to rebuild all indexes. This is the default mode.</p> |
| </li> |
| <li> |
| <p><code>fixOutdated</code> will check for outdated indexed document and reindex |
| only those.</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It’s good to note as well that there is a limitation with the |
| <code>fixOutdated</code> mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed <code>expunged</code> operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mailboxes?task=reIndex&messagesPerSecond=200&mode=rebuildAll</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>full-reindexing</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"full-reindexing", |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"REBUILD_ALL" |
| }, |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12", "23" ], |
| "messageFailures": [ |
| { |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_fixing_previously_failed_reindexing"><a class="anchor" href="#_fixing_previously_failed_reindexing"></a>Fixing previously failed ReIndexing</h5> |
| <div class="paragraph"> |
| <p>Will schedule a task for reIndexing all the mails which had failed to be |
| indexed from the ReIndexingAllMails task.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Given <code>bbdb69c9-082a-44b0-a85a-6e33e74287a5</code> being a <code>taskId</code> generated |
| for a reIndexing tasks</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST 'http://ip:port/mailboxes?task=reIndex&reIndexFailedMessagesOf=bbdb69c9-082a-44b0-a85a-6e33e74287a5'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed per |
| second. Default is 50.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can also specify the reindexing mode it wants to use when |
| running the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>mode</code> the reindexing mode used. There are 2 modes for the moment:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>rebuildAll</code> allows to rebuild all indexes. This is the default mode.</p> |
| </li> |
| <li> |
| <p><code>fixOutdated</code> will check for outdated indexed document and reindex |
| only those.</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It’s good to note as well that there is a limitation with the |
| <code>fixOutdated</code> mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed <code>expunged</code> operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mailboxes?task=reIndex&reIndexFailedMessagesOf=bbdb69c9-082a-44b0-a85a-6e33e74287a5&messagesPerSecond=200&mode=rebuildAll</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>error-recovery-indexation</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"error-recovery-indexation" |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"REBUILD_ALL" |
| }, |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12", "23" ], |
| "messageFailures": [{ |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect4"> |
| <h5 id="_create_missing_parent_mailboxes"><a class="anchor" href="#_create_missing_parent_mailboxes"></a>Create missing parent mailboxes</h5> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mailboxes?task=createMissingParents</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>createMissingParents</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"createMissingParents" |
| "created": ["1", "2" ], |
| "totalCreated": 2, |
| "failures": [], |
| "totalFailure": 0 |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_single_mailbox"><a class="anchor" href="#_single_mailbox"></a>Single mailbox</h3> |
| <div class="sect3"> |
| <h4 id="_reindexing_a_mailbox_mails"><a class="anchor" href="#_reindexing_a_mailbox_mails"></a>ReIndexing a mailbox mails</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mailboxes/{mailboxId}?task=reIndex</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for reIndexing all the mails in one mailbox.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that `mailboxId' path parameter needs to be a (implementation |
| dependent) valid mailboxId.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed per |
| second. Default is 50.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can also specify the reindexing mode it wants to use when |
| running the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>mode</code> the reindexing mode used. There are 2 modes for the moment:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>rebuildAll</code> allows to rebuild all indexes. This is the default mode.</p> |
| </li> |
| <li> |
| <p><code>fixOutdated</code> will check for outdated indexed document and reindex |
| only those.</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It’s good to note as well that there is a limitation with the |
| <code>fixOutdated</code> mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed <code>expunged</code> operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mailboxes/{mailboxId}?task=reIndex&messagesPerSecond=200&mode=fixOutdated</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>mailbox-reindexing</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"mailbox-reindexing", |
| "runningOptions":{ |
| "messagesPerSecond":200, |
| "mode":"FIX_OUTDATED" |
| }, |
| "mailboxId":"{mailboxId}", |
| "successfullyReprocessedMailCount":18, |
| "failedReprocessedMailCount": 3, |
| "mailboxFailures": ["12"], |
| "messageFailures": [ |
| { |
| "mailboxId": "1", |
| "uids": [1, 36] |
| }] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: During the re-indexing, the result of search operations might |
| be altered.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: Canceling this task should be considered unsafe as it will |
| leave the currently reIndexed mailbox as partially indexed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_messages"><a class="anchor" href="#_administrating_messages"></a>Administrating Messages</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_reindexing_a_single_mail_by_messageid"><a class="anchor" href="#_reindexing_a_single_mail_by_messageid"></a>ReIndexing a single mail by messageId</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/messages/{messageId}?task=reIndex</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for reIndexing a single email in all the mailboxes |
| containing it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that `messageId' path parameter needs to be a (implementation |
| dependent) valid messageId.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>messageId-reindexing</code> |
| and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "messageId":"18" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: During the re-indexing, the result of search operations might |
| be altered.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_fixing_message_inconsistencies"><a class="anchor" href="#_fixing_message_inconsistencies"></a>Fixing message inconsistencies</h3> |
| <div class="paragraph"> |
| <p>This task is only available on top of Guice Cassandra products.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /messages?task=SolveInconsistencies</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for fixing message inconsistencies created by the |
| message denormalization process.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Messages are denormalized and stored in separated data tables in |
| Cassandra, so they can be accessed by their unique identifier or mailbox |
| identifier & local mailbox identifier through different protocols.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Failure in the denormalization process will lead to inconsistencies, for |
| example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>BOB receives a message |
| The denormalization process fails |
| BOB can read the message via JMAP |
| BOB cannot read the message via IMAP |
| |
| BOB marks a message as SEEN |
| The denormalization process fails |
| The message is SEEN via JMAP |
| The message is UNSEEN via IMAP</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate of messages to be processed per second. |
| Default is 100.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can also specify the reindexing mode it wants to use when |
| running the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>mode</code> the reindexing mode used. There are 2 modes for the moment:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>rebuildAll</code> allows to rebuild all indexes. This is the default mode.</p> |
| </li> |
| <li> |
| <p><code>fixOutdated</code> will check for outdated indexed document and reindex |
| only those.</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It’s good to note as well that there is a limitation with the |
| <code>fixOutdated</code> mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed <code>expunged</code> operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /messages?task=SolveInconsistencies&messagesPerSecond=200&mode=rebuildAll</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>solve-message-inconsistencies</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"solve-message-inconsistencies", |
| "timestamp":"2007-12-03T10:15:30Z", |
| "processedImapUidEntries": 2, |
| "processedMessageIdEntries": 1, |
| "addedMessageIdEntries": 1, |
| "updatedMessageIdEntries": 0, |
| "removedMessageIdEntries": 1, |
| "runningOptions":{ |
| "messagesPerSecond": 200, |
| "mode":"REBUILD_ALL" |
| }, |
| "fixedInconsistencies": [ |
| { |
| "mailboxId": "551f0580-82fb-11ea-970e-f9c83d4cf8c2", |
| "messageId": "d2bee791-7e63-11ea-883c-95b84008f979", |
| "uid": 1 |
| }, |
| { |
| "mailboxId": "551f0580-82fb-11ea-970e-f9c83d4cf8c2", |
| "messageId": "d2bee792-7e63-11ea-883c-95b84008f979", |
| "uid": 2 |
| } |
| ], |
| "errors": [ |
| { |
| "mailboxId": "551f0580-82fb-11ea-970e-f9c83d4cf8c2", |
| "messageId": "ffffffff-7e63-11ea-883c-95b84008f979", |
| "uid": 3 |
| } |
| ] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>User actions concurrent to the inconsistency fixing task could result in |
| concurrency issues. New inconsistencies could be created.</p> |
| </div> |
| <div class="paragraph"> |
| <p>However the source of truth will not be impacted, hence rerunning the |
| task will eventually fix all issues.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This task could be run safely online and can be scheduled on a recurring |
| basis outside of peak traffic by an admin to ensure Cassandra message |
| consistency.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_old_messages_of_all_users"><a class="anchor" href="#_deleting_old_messages_of_all_users"></a>Deleting old messages of all users</h3> |
| <div class="paragraph"> |
| <p><strong>Note:</strong> |
| Consider enabling the <a href="../configure/vault.html" class="xref page">Deleted Messages Vault</a> |
| if you use this feature.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/messages?olderThan=30d</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>olderThan</code> parameter should be expressed in the following format: <code>Nunit</code>. |
| <code>N</code> should be strictly positive. <code>unit</code> could be either in the short form |
| (<code>d</code>, <code>w</code>, <code>y</code> etc.), or in the long form (<code>days</code>, <code>weeks</code>, <code>months</code>, <code>years</code>). |
| The default unit is <code>days</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the type <code>ExpireMailboxTask</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type": "ExpireMailboxTask" |
| "mailboxesExpired": 5, |
| "mailboxesFailed": 2, |
| "mailboxesProcessed": 10, |
| "messagesDeleted": 23, |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To delete old mails from a different mailbox than INBOX, e.g. a mailbox |
| named "Archived" :</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/messages?mailbox=Archived&olderThan=30d</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Since this is a somewhat expensive operation, the task is throttled to one user |
| per second. You may speed it up via <code>usersPerSecond=10</code> for example. But keep |
| in mind that a high rate might overwhelm your database or blob store.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Scanning search only:</strong> (unsupported for Lucene and OpenSearch search implementations)<br> |
| Some mail clients can add an <code>Expires</code> 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:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/messages?byExpiresHeader</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In this case you should also add the <a href="../configure/mailets.html" class="xref page">mailet</a> |
| <code>Expires</code> to your mailet container, which can sanitize expiration date headers.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_user_mailboxes"><a class="anchor" href="#_administrating_user_mailboxes"></a>Administrating user mailboxes</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_creating_a_mailbox"><a class="anchor" href="#_creating_a_mailbox"></a>Creating a mailbox</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxNameToBeCreated}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user Resource |
| name <code>mailboxNameToBeCreated</code> should not be empty, nor contain % * characters, nor starting with #.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The mailbox now exists on the server</p> |
| </li> |
| <li> |
| <p>400: Invalid mailbox name</p> |
| </li> |
| <li> |
| <p>404: The user name does not exist. Note that this check can be bypassed by specifying the <code>force</code> query parameter.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>To create nested mailboxes, for instance a work mailbox inside the INBOX |
| mailbox, people should use the . separator. The sample query is:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes/INBOX.work</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_a_mailbox_and_its_children"><a class="anchor" href="#_deleting_a_mailbox_and_its_children"></a>Deleting a mailbox and its children</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxNameToBeDeleted}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user Resource |
| name <code>mailboxNameToBeDeleted</code> should not be empty</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The mailbox now does not exist on the server</p> |
| </li> |
| <li> |
| <p>400: Invalid mailbox name</p> |
| </li> |
| <li> |
| <p>404: The user name does not exist. Note that this check can be bypassed by specifying the <code>force</code> query parameter.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_testing_existence_of_a_mailbox"><a class="anchor" href="#_testing_existence_of_a_mailbox"></a>Testing existence of a mailbox</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxNameToBeTested}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user Resource |
| name <code>mailboxNameToBeTested</code> should not be empty</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The mailbox exists</p> |
| </li> |
| <li> |
| <p>400: Invalid mailbox name</p> |
| </li> |
| <li> |
| <p>404: The user name does not exist, the mailbox does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_user_mailboxes"><a class="anchor" href="#_listing_user_mailboxes"></a>Listing user mailboxes</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[{"mailboxName":"INBOX"},{"mailboxName":"outbox"}]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The mailboxes list was successfully retrieved</p> |
| </li> |
| <li> |
| <p>404: The user name does not exist, the mailbox does not exist. Note that this check can be bypassed by specifying the <code>force</code> query parameter.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_user_mailboxes"><a class="anchor" href="#_deleting_user_mailboxes"></a>Deleting user mailboxes</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The user do not have mailboxes anymore</p> |
| </li> |
| <li> |
| <p>404: The user name does not exist. Note that this check can be bypassed by specifying the <code>force</code> query parameter.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_exporting_user_mailboxes"><a class="anchor" href="#_exporting_user_mailboxes"></a>Exporting user mailboxes</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?action=export</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned</p> |
| </li> |
| <li> |
| <p>404: The user name does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>MailboxesExportTask</code> |
| and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"MailboxesExportTask", |
| "timestamp":"2007-12-03T10:15:30Z", |
| "username": "user", |
| "stage": "STARTING" |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_reindexing_a_user_mails"><a class="anchor" href="#_reindexing_a_user_mails"></a>ReIndexing a user mails</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?task=reIndex</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for reIndexing all the mails in ``<a href="mailto:user@domain.com">user@domain.com</a>'' |
| mailboxes (encoded above).</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed per |
| second. Default is 50.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can also specify the reindexing mode it wants to use when |
| running the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>mode</code> the reindexing mode used. There are 2 modes for the moment:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>rebuildAll</code> allows to rebuild all indexes. This is the default mode.</p> |
| </li> |
| <li> |
| <p><code>fixOutdated</code> will check for outdated indexed document and reindex |
| only those.</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must be passed as query parameter.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It’s good to note as well that there is a limitation with the |
| <code>fixOutdated</code> mode. As we first collect metadata of stored messages to |
| compare them with the ones in the index, a failed <code>expunged</code> operation |
| might not be well corrected (as the message might not exist anymore but |
| still be indexed).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?task=reIndex&messagesPerSecond=200&mode=fixOutdated</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>user-reindexing</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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] |
| }] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: During the re-indexing, the result of search operations might |
| be altered.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Warning: Canceling this task should be considered unsafe as it will |
| leave the currently reIndexed mailbox as partially indexed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_counting_emails"><a class="anchor" href="#_counting_emails"></a>Counting emails</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/messageCount</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the total count of messages within the mailbox of that user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>mailboxName</code> should not be empty, nor contain <code>% *</code> characters, nor starting with <code>#</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The number of emails in a given mailbox</p> |
| </li> |
| <li> |
| <p>400: Invalid mailbox name</p> |
| </li> |
| <li> |
| <p>404: Invalid get on user mailboxes. The <code>usernameToBeUsed</code> or <code>mailboxName</code> does not exit'</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_counting_unseen_emails"><a class="anchor" href="#_counting_unseen_emails"></a>Counting unseen emails</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/unseenMessageCount</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the total count of unseen messages within the mailbox of that user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>mailboxName</code> should not be empty, nor contain <code>% *</code> characters, nor starting with <code>#</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The number of unseen emails in a given mailbox</p> |
| </li> |
| <li> |
| <p>400: Invalid mailbox name</p> |
| </li> |
| <li> |
| <p>404: Invalid get on user mailboxes. The <code>usernameToBeUsed</code> or <code>mailboxName</code> does not exit'</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_clearing_mailbox_content"><a class="anchor" href="#_clearing_mailbox_content"></a>Clearing mailbox content</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/users/{usernameToBeUsed}/mailboxes/{mailboxName}/messages</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for clearing all the mails in <code>mailboxName</code> mailbox of <code>usernameToBeUsed</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>mailboxName</code> should not be empty, nor contain <code>% *</code> characters, nor starting with <code>#</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Invalid mailbox name</p> |
| </li> |
| <li> |
| <p>404: Invalid get on user mailboxes. The <code>username</code> or <code>mailboxName</code> does not exit</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>ClearMailboxContentTask</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "mailboxName": "mbx1", |
| "messagesFailCount": 9, |
| "messagesSuccessCount": 10, |
| "timestamp": "2007-12-03T10:15:30Z", |
| "type": "ClearMailboxContentTask", |
| "username": "bob@domain.tld" |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_subscribing_a_user_to_all_of_its_mailboxes"><a class="anchor" href="#_subscribing_a_user_to_all_of_its_mailboxes"></a>Subscribing a user to all of its mailboxes</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/users/{usernameToBeUsed}/mailboxes?task=subscribeAll</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for subscribing a user to all of its mailboxes.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>404: No such user</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>SubscribeAllTask</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"SubscribeAllTask", |
| "username":"user@domain.com", |
| "subscribedCount":18, |
| "unsubscribedCount": 3 |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_recomputing_user_jmap_fast_message_view_projection"><a class="anchor" href="#_recomputing_user_jmap_fast_message_view_projection"></a>Recomputing User JMAP fast message view projection</h3> |
| <div class="paragraph"> |
| <p>This action is only available for backends supporting JMAP protocol.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These projection items are asynchronously computed on mailbox events.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can force the full projection recomputation by calling the following |
| endpoint:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /users/{usernameToBeUsed}/mailboxes?task=recomputeFastViewProjectionItems</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for recomputing the fast message view projection |
| for all mailboxes of <code>usernameToBeUsed</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>messagesPerSecond</code> rate at which messages should be processed, per |
| second. Defaults to 10.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mailboxes?task=recomputeFastViewProjectionItems&messagesPerSecond=20</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>RecomputeUserFastViewProjectionItemsTask</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"RecomputeUserFastViewProjectionItemsTask", |
| "username": "{usernameToBeUsed}", |
| "processedMessageCount": 3, |
| "failedMessageCount": 1, |
| "runningOptions": { |
| "messagesPerSecond":20 |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Error in the request. Details can be found in the reported error.</p> |
| </li> |
| <li> |
| <p>404: User not found.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_quotas"><a class="anchor" href="#_administrating_quotas"></a>Administrating quotas</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_administrating_quotas_by_users"><a class="anchor" href="#_administrating_quotas_by_users"></a>Administrating quotas by users</h3> |
| <div class="sect3"> |
| <h4 id="_getting_the_quota_for_a_user"><a class="anchor" href="#_getting_the_quota_for_a_user"></a>Getting the quota for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/users/{usernameToBeUsed}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The answer is the details of the quota of that user.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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 |
| } |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The <code>global</code> entry represent the quota limit allowed on this James |
| server.</p> |
| </li> |
| <li> |
| <p>The <code>domain</code> entry represent the quota limit allowed for the user of |
| that domain.</p> |
| </li> |
| <li> |
| <p>The <code>user</code> entry represent the quota limit allowed for this specific |
| user.</p> |
| </li> |
| <li> |
| <p>The <code>computed</code> entry represent the quota limit applied for this user, |
| resolved from the upper values.</p> |
| </li> |
| <li> |
| <p>The <code>occupation</code> entry represent the occupation of the quota for this |
| user. This includes used count and size as well as occupation ratio |
| (used / limit).</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note that <code>quota</code> object can contain a fixed value, an empty value |
| (null) or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The user’s quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_quota_for_a_user"><a class="anchor" href="#_updating_the_quota_for_a_user"></a>Updating the quota for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/users/{usernameToBeUsed}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value, an empty value (null) or an |
| unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_getting_the_quota_count_for_a_user"><a class="anchor" href="#_getting_the_quota_count_for_a_user"></a>Getting the quota count for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/users/{usernameToBeUsed}/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The user’s quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>204: No quota count limit is defined at the user level for this user</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_quota_count_for_a_user"><a class="anchor" href="#_updating_the_quota_count_for_a_user"></a>Updating the quota count for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/users/{usernameToBeUsed}/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_deleting_the_quota_count_for_a_user"><a class="anchor" href="#_deleting_the_quota_count_for_a_user"></a>Deleting the quota count for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/quota/users/{usernameToBeUsed}/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated to unlimited value.</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_getting_the_quota_size_for_a_user"><a class="anchor" href="#_getting_the_quota_size_for_a_user"></a>Getting the quota size for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/users/{usernameToBeUsed}/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The user’s quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>204: No quota size limit is defined at the user level for this user</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_quota_size_for_a_user"><a class="anchor" href="#_updating_the_quota_size_for_a_user"></a>Updating the quota size for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/users/{usernameToBeUsed}/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_deleting_the_quota_size_for_a_user"><a class="anchor" href="#_deleting_the_quota_size_for_a_user"></a>Deleting the quota size for a user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/quota/users/{usernameToBeUsed}/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>usernameToBeUsed</code> should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated to unlimited value.</p> |
| </li> |
| <li> |
| <p>404: The user does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_searching_user_by_quota_ratio"><a class="anchor" href="#_searching_user_by_quota_ratio"></a>Searching user by quota ratio</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET 'http://ip:port/quota/users?minOccupationRatio=0.8&maxOccupationRatio=0.99&limit=100&offset=200&domain=domain.com'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| { |
| "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 |
| } |
| } |
| } |
| }, |
| ... |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>minOccupationRatio</strong> is a query parameter determining the minimum |
| occupation ratio of users to be returned.</p> |
| </li> |
| <li> |
| <p><strong>maxOccupationRatio</strong> is a query parameter determining the maximum |
| occupation ratio of users to be returned.</p> |
| </li> |
| <li> |
| <p><strong>domain</strong> is a query parameter determining the domain of users to be |
| returned.</p> |
| </li> |
| <li> |
| <p><strong>limit</strong> is a query parameter determining the maximum number of users |
| to be returned.</p> |
| </li> |
| <li> |
| <p><strong>offset</strong> is a query parameter determining the number of users to skip.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Please note that users are alphabetically ordered on username.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The response is a list of usernames, with attached quota details as |
| defined <a href="#_getting_the_quota_for_a_user">here</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: List of users had successfully been returned.</p> |
| </li> |
| <li> |
| <p>400: Validation issues with parameters</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_recomputing_current_quotas_for_users"><a class="anchor" href="#_recomputing_current_quotas_for_users"></a>Recomputing current quotas for users</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /quota/users?task=RecomputeCurrentQuotas</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will recompute current quotas (count and size) for all users stored in |
| James.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can specify the concurrency that should be used when running |
| the task:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>usersPerSecond</code> rate at which users quotas should be reprocessed, per |
| second. Defaults to 1.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This optional parameter must have a strictly positive integer as a value |
| and be passed as query parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An admin can select which quota component he wants to recompute:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>quotaComponent</code> component whose quota need to be reprocessed. It could be one of values: MAILBOX, SIEVE, JMAP_UPLOADS.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The admin could select several quota components. If he does not select, quotas of all components would be recomputed.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /quota/users?task=RecomputeCurrentQuotas&usersPerSecond=20&quotaComponent=MAILBOX&quotaComponent=JMAP_UPLOADS</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>recompute-current-quotas</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "type":"recompute-current-quotas", |
| "recomputeSingleQuotaComponentResults": [ |
| { |
| "quotaComponent": "MAILBOX", |
| "processedIdentifierCount": 3, |
| "failedIdentifiers": ["#private&bob@localhost"] |
| }, |
| { |
| "quotaComponent": "JMAP_UPLOADS", |
| "processedIdentifierCount": 3, |
| "failedIdentifiers": ["bob@localhost"] |
| } |
| ], |
| "runningOptions": { |
| "usersPerSecond":20 |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>WARNING</strong>: this task do not take into account concurrent modifications |
| upon a single current quota re-computation. Rerunning the task will |
| <em>eventually</em> provide the consistent result.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_administrating_quotas_by_domains"><a class="anchor" href="#_administrating_quotas_by_domains"></a>Administrating quotas by domains</h3> |
| <div class="sect3"> |
| <h4 id="_getting_the_quota_for_a_domain"><a class="anchor" href="#_getting_the_quota_for_a_domain"></a>Getting the quota for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/domains/{domainToBeUsed}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain. For |
| example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/domains/james.org</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer will detail the default quota applied to users belonging to |
| that domain:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "global": { |
| "count":252, |
| "size":null |
| }, |
| "domain": { |
| "count":null, |
| "size":142 |
| }, |
| "computed": { |
| "count":252, |
| "size":142 |
| } |
| }</pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The <code>global</code> entry represents the quota limit defined on this James |
| server by default.</p> |
| </li> |
| <li> |
| <p>The <code>domain</code> entry represents the quota limit allowed for the user of |
| that domain by default.</p> |
| </li> |
| <li> |
| <p>The <code>computed</code> entry represents the quota limit applied for the users |
| of that domain, by default, resolved from the upper values.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note that <code>quota</code> object can contain a fixed value, an empty value |
| (null) or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The domain’s quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| deactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_quota_for_a_domain"><a class="anchor" href="#_updating_the_quota_for_a_domain"></a>Updating the quota for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/domains/{domainToBeUsed}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value, an empty value (null) or an |
| unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| deactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_getting_the_quota_count_for_a_domain"><a class="anchor" href="#_getting_the_quota_count_for_a_domain"></a>Getting the quota count for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/domains/{domainToBeUsed}/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The domain’s quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>204: No quota count limit is defined at the domain level for this |
| domain</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| desactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_quota_count_for_a_domain"><a class="anchor" href="#_updating_the_quota_count_for_a_domain"></a>Updating the quota count for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/domains/{domainToBeUsed}/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| desactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_deleting_the_quota_count_for_a_domain"><a class="anchor" href="#_deleting_the_quota_count_for_a_domain"></a>Deleting the quota count for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/quota/domains/{domainToBeUsed}/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated to unlimited value.</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| deactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_getting_the_quota_size_for_a_domain"><a class="anchor" href="#_getting_the_quota_size_for_a_domain"></a>Getting the quota size for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/domains/{domainToBeUsed}/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The domain’s quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>204: No quota size limit is defined at the domain level for this |
| domain</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| deactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_quota_size_for_a_domain"><a class="anchor" href="#_updating_the_quota_size_for_a_domain"></a>Updating the quota size for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/domains/{domainToBeUsed}/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| <li> |
| <p>405: Domain Quota configuration not supported when virtual hosting is |
| deactivated.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_deleting_the_quota_size_for_a_domain"><a class="anchor" href="#_deleting_the_quota_size_for_a_domain"></a>Deleting the quota size for a domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/quota/domains/{domainToBeUsed}/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>domainToBeUsed</code> should be an existing domain.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated to unlimited value.</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_administrating_global_quotas"><a class="anchor" href="#_administrating_global_quotas"></a>Administrating global quotas</h3> |
| <div class="sect3"> |
| <h4 id="_getting_the_global_quota"><a class="anchor" href="#_getting_the_global_quota"></a>Getting the global quota</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer is the details of the global quota.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "count":252, |
| "size":242 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that <code>quota</code> object can contain a fixed value, an empty value |
| (null) or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The quota was successfully retrieved</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_global_quota"><a class="anchor" href="#_updating_global_quota"></a>Updating global quota</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value, an empty value (null) or an |
| unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"count":52,"size":42} |
| |
| {"count":null,"size":null} |
| |
| {"count":52,"size":-1}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_getting_the_global_quota_count"><a class="anchor" href="#_getting_the_global_quota_count"></a>Getting the global quota count</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name usernameToBeUsed should be an existing user</p> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>204: No quota count limit is defined at the global level</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_global_quota_count"><a class="anchor" href="#_updating_the_global_quota_count"></a>Updating the global quota count</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_deleting_the_global_quota_count"><a class="anchor" href="#_deleting_the_global_quota_count"></a>Deleting the global quota count</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/quota/count</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated to unlimited value.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_getting_the_global_quota_size"><a class="anchor" href="#_getting_the_global_quota_size"></a>Getting the global quota size</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/quota/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The quota was successfully retrieved</p> |
| </li> |
| <li> |
| <p>204: No quota size limit is defined at the global level</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_the_global_quota_size"><a class="anchor" href="#_updating_the_global_quota_size"></a>Updating the global quota size</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/quota/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a fixed value or an unlimited value (-1):</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>52</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated</p> |
| </li> |
| <li> |
| <p>400: The body is not a positive integer neither an unlimited value |
| (-1).</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_deleting_the_global_quota_size"><a class="anchor" href="#_deleting_the_global_quota_size"></a>Deleting the global quota size</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/quota/size</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The quota has been updated to unlimited value.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_administrating_sieve_quotas"><a class="anchor" href="#_administrating_sieve_quotas"></a>Administrating Sieve quotas</h3> |
| <div class="paragraph"> |
| <p>Some limitations on space Users Sieve script can occupy can be |
| configured by default, and overridden by user.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_retrieving_global_sieve_quota"><a class="anchor" href="#_retrieving_global_sieve_quota"></a>Retrieving global sieve quota</h4> |
| <div class="paragraph"> |
| <p>This endpoints allows to retrieve the global Sieve quota, which will be |
| users default:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/sieve/quota/default</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the bytes count allowed by user per default on this server.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>102400</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Request is a success and the value is returned</p> |
| </li> |
| <li> |
| <p>204: No default quota is being configured</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_global_sieve_quota"><a class="anchor" href="#_updating_global_sieve_quota"></a>Updating global sieve quota</h4> |
| <div class="paragraph"> |
| <p>This endpoints allows to update the global Sieve quota, which will be |
| users default:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/sieve/quota/default</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>With the body being the bytes count allowed by user per default on this |
| server.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>102400</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Operation succeeded</p> |
| </li> |
| <li> |
| <p>400: Invalid payload</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_global_sieve_quota"><a class="anchor" href="#_removing_global_sieve_quota"></a>Removing global sieve quota</h4> |
| <div class="paragraph"> |
| <p>This endpoints allows to remove the global Sieve quota. There will no |
| more be users default:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/sieve/quota/default</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Operation succeeded</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_retrieving_user_sieve_quota"><a class="anchor" href="#_retrieving_user_sieve_quota"></a>Retrieving user sieve quota</h4> |
| <div class="paragraph"> |
| <p>This endpoints allows to retrieve the Sieve quota of a user, which will |
| be this users quota:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/sieve/quota/users/user@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the bytes count allowed for this user.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>102400</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Request is a success and the value is returned</p> |
| </li> |
| <li> |
| <p>204: No quota is being configured for this user</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_updating_user_sieve_quota"><a class="anchor" href="#_updating_user_sieve_quota"></a>Updating user sieve quota</h4> |
| <div class="paragraph"> |
| <p>This endpoints allows to update the Sieve quota of a user, which will be |
| users default:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/sieve/quota/users/user@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>With the body being the bytes count allowed for this user on this |
| server.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>102400</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Operation succeeded</p> |
| </li> |
| <li> |
| <p>400: Invalid payload</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_user_sieve_quota"><a class="anchor" href="#_removing_user_sieve_quota"></a>Removing user sieve quota</h4> |
| <div class="paragraph"> |
| <p>This endpoints allows to remove the Sieve quota of a user. There will no |
| more quota for this user:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/sieve/quota/users/user@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Operation succeeded</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_jmap_uploads"><a class="anchor" href="#_administrating_jmap_uploads"></a>Administrating Jmap Uploads</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_cleaning_upload_repository"><a class="anchor" href="#_cleaning_upload_repository"></a>Cleaning upload repository</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/jmap/uploads?scope=expired</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule a task for clearing expired upload entries.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Query parameter <code>scope</code> is required and have the value <code>expired</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Success. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Scope invalid</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>UploadRepositoryCleanupTask</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "scope": "expired", |
| "timestamp": "2007-12-03T10:15:30Z", |
| "type": "UploadRepositoryCleanupTask" |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_running_blob_garbage_collection"><a class="anchor" href="#_running_blob_garbage_collection"></a>Running blob garbage collection</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>When deduplication is enabled one needs to explicitly run a garbage collection in order to delete no longer referenced |
| blobs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To do so:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/blobs?scope=unreferenced</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Additional parameters include Bloom filter tuning parameters:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>associatedProbability</strong>: Allow to define the targeted false positive rate. Note that subsequent runs do not have the |
| same false-positives. Defaults to <code>0.01</code>.</p> |
| </li> |
| <li> |
| <p><strong>expectedBlobCount</strong>: Expected count of blobs used to size the bloom filters. Defaults to <code>1.000.000</code>.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>These settings directly impacts the memory footprint of the bloom filter. <a href="https://hur.st/bloomfilter/">Simulators</a> can |
| help understand those parameters.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The created task has the following additional information:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "referenceSourceCount": 3456, |
| "blobCount": 5678, |
| "gcedBlobCount": 1234, |
| "bloomFilterExpectedBlobCount": 10000, |
| "bloomFilterAssociatedProbability": 0.01 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>bloomFilterExpectedBlobCount</strong> correspond to the supplied <strong>expectedBlobCount</strong> query parameter.</p> |
| </li> |
| <li> |
| <p><strong>bloomFilterAssociatedProbability</strong> correspond to the supplied <strong>associatedProbability</strong> query parameter.</p> |
| </li> |
| <li> |
| <p><strong>referenceSourceCount</strong> is the count of distinct blob references encountered while populating the bloom filter.</p> |
| </li> |
| <li> |
| <p><strong>blobCount</strong> is the count of blobs tried against the bloom filter. This value can be used to better size the bloom |
| filter in later runs.</p> |
| </li> |
| <li> |
| <p><strong>gcedBlobCount</strong> is the count of blobs that were garbage collected.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_recipient_rewriting"><a class="anchor" href="#_administrating_recipient_rewriting"></a>Administrating Recipient rewriting</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_address_group"><a class="anchor" href="#_address_group"></a>Address group</h3> |
| <div class="paragraph"> |
| <p>You can use <strong>webadmin</strong> to define address groups.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a specific email is sent to the group mail address, every group |
| member will receive it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the group mail address is virtual: it does not correspond to |
| an existing user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This feature uses <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a> |
| and requires the |
| <a href="https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java">RecipientRewriteTable |
| mailet</a> to be configured.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_groups"><a class="anchor" href="#_listing_groups"></a>Listing groups</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/address/groups</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the groups as a list of JSON Strings representing mail |
| addresses. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["group1@domain.com", "group2@domain.com"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_members_of_a_group"><a class="anchor" href="#_listing_members_of_a_group"></a>Listing members of a group</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/address/groups/group@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the group members as a list of JSON Strings representing |
| mail addresses. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["member1@domain.com", "member2@domain.com"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| <li> |
| <p>400: Group structure is not valid</p> |
| </li> |
| <li> |
| <p>404: The group does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_adding_a_group_member"><a class="anchor" href="#_adding_a_group_member"></a>Adding a group member</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/address/groups/group@domain.com/member@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will add <a href="mailto:member@domain.com">member@domain.com</a> to <a href="mailto:group@domain.com">group@domain.com</a>, creating the group if |
| needed</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success</p> |
| </li> |
| <li> |
| <p>400: Group structure or member is not valid</p> |
| </li> |
| <li> |
| <p>400: Domain in the source is not managed by the DomainList</p> |
| </li> |
| <li> |
| <p>409: Requested group address is already used for another purpose</p> |
| </li> |
| <li> |
| <p>409: The addition of the group member would lead to a loop and thus cannot be performed</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_a_group_member"><a class="anchor" href="#_removing_a_group_member"></a>Removing a group member</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/address/groups/group@domain.com/member@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will remove <a href="mailto:member@domain.com">member@domain.com</a> from <a href="mailto:group@domain.com">group@domain.com</a>, removing the group |
| if group is empty after deletion</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success</p> |
| </li> |
| <li> |
| <p>400: Group structure or member is not valid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_address_forwards"><a class="anchor" href="#_address_forwards"></a>Address forwards</h3> |
| <div class="paragraph"> |
| <p>You can use <strong>webadmin</strong> to define address forwards.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a specific email is sent to the base mail address, every forward |
| destination addresses will receive it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Forwards can be defined for existing users. It then defers from |
| ``groups''.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This feature uses <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a> |
| and requires the |
| <a href="https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java">RecipientRewriteTable |
| mailet</a> to be configured.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_forwards"><a class="anchor" href="#_listing_forwards"></a>Listing Forwards</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/address/forwards</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the users having forwards configured as a list of JSON |
| Strings representing mail addresses. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["user1@domain.com", "user2@domain.com"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_destinations_in_a_forward"><a class="anchor" href="#_listing_destinations_in_a_forward"></a>Listing destinations in a forward</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/address/forwards/user@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the destination addresses of this forward as a list of JSON |
| Strings representing mail addresses. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| {"mailAddress":"destination1@domain.com"}, |
| {"mailAddress":"destination2@domain.com"} |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| <li> |
| <p>400: Forward structure is not valid</p> |
| </li> |
| <li> |
| <p>404: The given user don’t have forwards or does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_adding_a_new_destination_to_a_forward"><a class="anchor" href="#_adding_a_new_destination_to_a_forward"></a>Adding a new destination to a forward</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/address/forwards/user@domain.com/targets/destination@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will add <a href="mailto:destination@domain.com">destination@domain.com</a> to <a href="mailto:user@domain.com">user@domain.com</a>, creating the forward |
| if needed</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success</p> |
| </li> |
| <li> |
| <p>400: Forward structure or member is not valid</p> |
| </li> |
| <li> |
| <p>400: Domain in the source is not managed by the DomainList</p> |
| </li> |
| <li> |
| <p>404: Requested forward address does not match an existing user</p> |
| </li> |
| <li> |
| <p>409: The creation of the forward would lead to a loop and thus cannot be performed</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_a_destination_of_a_forward"><a class="anchor" href="#_removing_a_destination_of_a_forward"></a>Removing a destination of a forward</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/address/forwards/user@domain.com/targets/destination@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will remove <a href="mailto:destination@domain.com">destination@domain.com</a> from <a href="mailto:user@domain.com">user@domain.com</a>, removing the |
| forward if forward is empty after deletion</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success</p> |
| </li> |
| <li> |
| <p>400: Forward structure or member is not valid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_address_aliases"><a class="anchor" href="#_address_aliases"></a>Address aliases</h3> |
| <div class="paragraph"> |
| <p>You can use <strong>webadmin</strong> to define aliases for an user.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a specific email is sent to the alias address, the destination |
| address of the alias will receive it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Aliases can be defined for existing users.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This feature uses <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a> |
| and requires the |
| <a href="https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java">RecipientRewriteTable |
| mailet</a> to be configured.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_users_with_aliases"><a class="anchor" href="#_listing_users_with_aliases"></a>Listing users with aliases</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/address/aliases</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the users having aliases configured as a list of JSON |
| Strings representing mail addresses. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["user1@domain.com", "user2@domain.com"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_alias_sources_of_an_user"><a class="anchor" href="#_listing_alias_sources_of_an_user"></a>Listing alias sources of an user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/address/aliases/user@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the aliases of this user as a list of JSON Strings |
| representing mail addresses. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| {"source":"alias1@domain.com"}, |
| {"source":"alias2@domain.com"} |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| <li> |
| <p>400: Alias structure is not valid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_adding_a_new_alias_to_an_user"><a class="anchor" href="#_adding_a_new_alias_to_an_user"></a>Adding a new alias to an user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/address/aliases/user@domain.com/sources/alias@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will add <a href="mailto:alias@domain.com">alias@domain.com</a> to <a href="mailto:user@domain.com">user@domain.com</a>, creating the alias if |
| needed</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: OK</p> |
| </li> |
| <li> |
| <p>400: Alias structure or member is not valid</p> |
| </li> |
| <li> |
| <p>400: Source and destination can’t be the same!</p> |
| </li> |
| <li> |
| <p>400: Domain in the destination or source is not managed by the |
| DomainList</p> |
| </li> |
| <li> |
| <p>409: The alias source exists as an user already</p> |
| </li> |
| <li> |
| <p>409: The addition of the alias would lead to a loop and thus cannot be performed</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_an_alias_of_an_user"><a class="anchor" href="#_removing_an_alias_of_an_user"></a>Removing an alias of an user</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/address/aliases/user@domain.com/sources/alias@domain.com</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will remove <a href="mailto:alias@domain.com">alias@domain.com</a> from <a href="mailto:user@domain.com">user@domain.com</a>, removing the alias if |
| needed</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: OK</p> |
| </li> |
| <li> |
| <p>400: Alias structure or member is not valid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_domain_mappings"><a class="anchor" href="#_domain_mappings"></a>Domain mappings</h3> |
| <div class="paragraph"> |
| <p>You can use <strong>webadmin</strong> to define domain mappings.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example: with a source domain <code>james.apache.org</code> maps to two |
| destination domains <code>james.org</code> and <code>apache-james.org</code>, when a mail is |
| sent to <code>admin@james.apache.org</code>, then it will be routed to |
| <code>admin@james.org</code> and <code>admin@apache-james.org</code></p> |
| </div> |
| <div class="paragraph"> |
| <p>This feature uses <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a> |
| and requires the |
| <a href="https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java">RecipientRewriteTable |
| mailet</a> to be configured.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_all_domain_mappings"><a class="anchor" href="#_listing_all_domain_mappings"></a>Listing all domain mappings</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/domainMappings</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return all configured domain mappings</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "firstSource.org" : ["firstDestination.com", "secondDestination.net"], |
| "secondSource.com" : ["thirdDestination.com", "fourthDestination.net"], |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: OK</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_listing_all_destination_domains_for_a_source_domain"><a class="anchor" href="#_listing_all_destination_domains_for_a_source_domain"></a>Listing all destination domains for a source domain</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/domainMappings/sourceDomain.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>With <code>sourceDomain.tld</code> as the value passed to <code>fromDomain</code> resource |
| name, the API will return all destination domains configured to that |
| domain</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["firstDestination.com", "secondDestination.com"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: OK</p> |
| </li> |
| <li> |
| <p>400: The <code>fromDomain</code> resource name is invalid</p> |
| </li> |
| <li> |
| <p>404: The <code>fromDomain</code> resource name is not found</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_adding_a_domain_mapping"><a class="anchor" href="#_adding_a_domain_mapping"></a>Adding a domain mapping</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/domainMappings/sourceDomain.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Body:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>destination.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>With <code>sourceDomain.tld</code> as the value passed to <code>fromDomain</code> resource |
| name, the API will add a destination domain specified in the body to |
| that domain</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: OK</p> |
| </li> |
| <li> |
| <p>400: The <code>fromDomain</code> resource name is invalid</p> |
| </li> |
| <li> |
| <p>400: The destination domain specified in the body is invalid</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Be aware that no checks to find possible loops that would result of this creation will be performed.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_a_domain_mapping"><a class="anchor" href="#_removing_a_domain_mapping"></a>Removing a domain mapping</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/domainMappings/sourceDomain.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Body:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>destination.tld</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>With <code>sourceDomain.tld</code> as the value passed to <code>fromDomain</code> resource |
| name, the API will remove a destination domain specified in the body |
| mapped to that domain</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: OK</p> |
| </li> |
| <li> |
| <p>400: The <code>fromDomain</code> resource name is invalid</p> |
| </li> |
| <li> |
| <p>400: The destination domain specified in the body is invalid</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_regex_mapping"><a class="anchor" href="#_regex_mapping"></a>Regex mapping</h3> |
| <div class="paragraph"> |
| <p>You can use <strong>webadmin</strong> to create regex mappings.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This feature uses <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a> |
| and requires the |
| <a href="https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java">RecipientRewriteTable |
| API</a> to be configured.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_adding_a_regex_mapping"><a class="anchor" href="#_adding_a_regex_mapping"></a>Adding a regex mapping</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>POST /mappings/regex/mappingSource/targets/regex</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>the <code>mappingSource</code> is the path parameter represents for the Regex |
| Mapping mapping source</p> |
| </li> |
| <li> |
| <p>the <code>regex</code> is the path parameter represents for the Regex Mapping |
| regex</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The route will add a regex mapping made from <code>mappingSource</code> and <code>regex</code> |
| to RecipientRewriteTable.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mappings/regex/james@domain.tld/targets/james@.*:james-intern@james.org</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Mapping added successfully.</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>mappingSource</code> path parameter.</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>regex</code> path parameter.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Be aware that no checks to find possible loops that would result of this creation will be performed.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_removing_a_regex_mapping"><a class="anchor" href="#_removing_a_regex_mapping"></a>Removing a regex mapping</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>DELETE /mappings/regex/{mappingSource}/targets/{regex}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>the <code>mappingSource</code> is the path parameter representing the Regex |
| Mapping mapping source</p> |
| </li> |
| <li> |
| <p>the <code>regex</code> is the path parameter representing the Regex Mapping regex</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The route will remove the regex mapping made from <code>regex</code> from the |
| mapping source <code>mappingSource</code> to RecipientRewriteTable.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mappings/regex/james@domain.tld/targets/[O_O]:james-intern@james.org</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Mapping deleted successfully.</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>mappingSource</code> path parameter.</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>regex</code> path parameter.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_address_mappings"><a class="anchor" href="#_address_mappings"></a>Address Mappings</h3> |
| <div class="paragraph"> |
| <p>You can use <strong>webadmin</strong> to define address mappings.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a specific email is sent to the base mail address, every |
| destination addresses will receive it.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This feature uses <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a> |
| and requires the |
| <a href="https://github.com/apache/james-project/blob/master/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RecipientRewriteTable.java">RecipientRewriteTable |
| mailet</a> to be configured.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that email addresses are restricted to ASCII character set. Mail |
| addresses not matching this criteria will be rejected.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here are the following actions available on address mappings:</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_add_an_address_mapping"><a class="anchor" href="#_add_an_address_mapping"></a>Add an address mapping</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/mappings/address/{mappingSource}/targets/{destinationAddress}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>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</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Action successfully performed</p> |
| </li> |
| <li> |
| <p>400: Invalid parameters</p> |
| </li> |
| <li> |
| <p>409: The addition of the address mapping would lead to a loop and thus cannot be performed</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_remove_an_address_mapping"><a class="anchor" href="#_remove_an_address_mapping"></a>Remove an address mapping</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mappings/address/{mappingSource}/targets/{destinationAddress}</pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Remove an address mapping from the Recipients rewrite table</p> |
| </li> |
| <li> |
| <p>Mapping source is the value of <code>mappingSource</code></p> |
| </li> |
| <li> |
| <p>Mapping destination is the value of <code>destinationAddress</code></p> |
| </li> |
| <li> |
| <p>Type of mapping destination is Address</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Action successfully performed</p> |
| </li> |
| <li> |
| <p>400: Invalid parameters</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_list_all_mappings"><a class="anchor" href="#_list_all_mappings"></a>List all mappings</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mappings</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Get all mappings from the |
| <a href="../architecture/index.html#_recipient_rewrite_tables" class="xref page">Recipients rewrite table</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response body:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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" |
| } |
| ] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response code:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: OK</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_user_mappings"><a class="anchor" href="#_listing_user_mappings"></a>Listing User Mappings</h3> |
| <div class="paragraph"> |
| <p>This endpoint allows receiving all mappings of a corresponding user.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mappings/user/{userAddress}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Return all mappings of a user where:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>userAddress</code>: is the selected user</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response body:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| { |
| "type": "Address", |
| "mapping": "user123@domain.tld" |
| }, |
| { |
| "type": "Alias", |
| "mapping": "aliasuser123@domain.tld" |
| }, |
| { |
| "type": "Group", |
| "mapping": "group123@domain.tld" |
| } |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: OK</p> |
| </li> |
| <li> |
| <p>400: Invalid parameter value</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_mail_repositories"><a class="anchor" href="#_administrating_mail_repositories"></a>Administrating mail repositories</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_create_a_mail_repository"><a class="anchor" href="#_create_a_mail_repository"></a>Create a mail repository</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/mailRepositories/{encodedPathOfTheRepository}?protocol={someProtocol}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of the created mail repository. Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/mailRepositories/mailRepo?protocol=file</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: The repository is created</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_mail_repositories"><a class="anchor" href="#_listing_mail_repositories"></a>Listing mail repositories</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| { |
| "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" |
| } |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You can use <code>id</code>, the encoded URL of the repository, to access it in |
| later requests.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The list of mail repositories</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_getting_additional_information_for_a_mail_repository"><a class="anchor" href="#_getting_additional_information_for_a_mail_repository"></a>Getting additional information for a mail repository</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/{encodedPathOfTheRepository}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of an existing mail repository. Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "repository": "var/mail/error/", |
| "path": "mail%2Ferror%2F", |
| "size": 243 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Additonnal information for that repository</p> |
| </li> |
| <li> |
| <p>404: This repository can not be found</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_mails_contained_in_a_mail_repository"><a class="anchor" href="#_listing_mails_contained_in_a_mail_repository"></a>Listing mails contained in a mail repository</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of an existing mail repository. Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer will contains all mailKey contained in that repository.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[ |
| "mail-key-1", |
| "mail-key-2", |
| "mail-key-3" |
| ]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that this can be used to read mail details.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can pass additional URL parameters to this call in order to limit |
| the output: - A 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. - An offset: allow to skip elements. This |
| needs to be positive. Default value is zero.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET 'http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails?limit=100&offset=500'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The list of mail keys contained in that mail repository</p> |
| </li> |
| <li> |
| <p>400: Invalid parameters</p> |
| </li> |
| <li> |
| <p>404: This repository can not be found</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_readingdownloading_a_mail_details"><a class="anchor" href="#_readingdownloading_a_mail_details"></a>Reading/downloading a mail details</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/mailKey</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of an existing mail repository. Resource name <code>mailKey</code> should be the |
| key of a mail stored in that repository. Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/mail-key-1</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If the Accept header in the request is ``application/json'', then the |
| response looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If the Accept header in the request is ``message/rfc822'', then the |
| response will be the <em>eml</em> file itself.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Additional query parameter <code>additionalFields</code> add the existing |
| information to the response for the supported values (only work with |
| ``application/json'' Accept header):</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>attributes</p> |
| </li> |
| <li> |
| <p>headers</p> |
| </li> |
| <li> |
| <p>textBody</p> |
| </li> |
| <li> |
| <p>htmlBody</p> |
| </li> |
| <li> |
| <p>messageSize</p> |
| </li> |
| <li> |
| <p>perRecipientsHeaders</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailRepositories/file%3A%2F%2Fvar%2Fmail%2Ferror%2F/mails/mail-key-1?additionalFields=attributes,headers,textBody,htmlBody,messageSize,perRecipientsHeaders</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Give the following kind of response:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "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 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Details of the mail</p> |
| </li> |
| <li> |
| <p>404: This repository or mail can not be found</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_removing_a_mail_from_a_mail_repository"><a class="anchor" href="#_removing_a_mail_from_a_mail_repository"></a>Removing a mail from a mail repository</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/mailKey</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of an existing mail repository. Resource name <code>mailKey</code> should be the |
| key of a mail stored in that repository. Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/mail-key-1</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: This mail no longer exists in this repository</p> |
| </li> |
| <li> |
| <p>404: This repository can not be found</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_removing_all_mails_from_a_mail_repository"><a class="anchor" href="#_removing_all_mails_from_a_mail_repository"></a>Removing all mails from a mail repository</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of an existing mail repository. Example:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>404: Could not find that mail repository</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>clear-mail-repository</code> |
| and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "mailRepositoryPath":"var/mail/error/", |
| "initialCount": 243, |
| "remainingCount": 17 |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_reprocessing_mails_from_a_mail_repository"><a class="anchor" href="#_reprocessing_mails_from_a_mail_repository"></a>Reprocessing mails from a mail repository</h3> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To reprocess mails from a repository:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails?action=reprocess</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource path |
| of an existing mail repository. Example:</p> |
| </div> |
| <div class="paragraph"> |
| <p>For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails?action=reprocess</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Additional query parameters are supported:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>queue</code> allows you to |
| target the mail queue you want to enqueue the mails in. Defaults to |
| <code>spool</code>.</p> |
| </li> |
| <li> |
| <p><code>processor</code> allows you to overwrite the state of the |
| reprocessing mails, and thus select the processors they will start their |
| processing in. Defaults to the <code>state</code> field of each processed email.</p> |
| </li> |
| <li> |
| <p><code>consume</code> (boolean defaulting to <code>true</code>) whether the reprocessing should consume the mail in its originating mail repository. Passing |
| this value to <code>false</code> allows non destructive reprocessing as you keep a copy of the email in the mail repository and can be valuable |
| when debugging.</p> |
| </li> |
| <li> |
| <p><code>limit</code> (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.</p> |
| </li> |
| <li> |
| <p><code>maxRetries</code> Optional integer, defaults to no max retries limit. Only processed emails that had been retried less |
| than this value. Ignored by default.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>redeliver_group_events</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH 'http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails?action=reprocess&processor=transport&queue=spool'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the <code>action</code> query parameter is compulsary and can only take |
| value <code>reprocess</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>404: Could not find that mail repository</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>reprocessing-all</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "mailRepositoryPath":"var/mail/error/", |
| "targetQueue":"spool", |
| "targetProcessor":"transport", |
| "initialCount": 243, |
| "remainingCount": 17 |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_reprocessing_a_specific_mail_from_a_mail_repository"><a class="anchor" href="#_reprocessing_a_specific_mail_from_a_mail_repository"></a>Reprocessing a specific mail from a mail repository</h3> |
| <div class="paragraph"> |
| <p>To reprocess a specific mail from a mail repository:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH http://ip:port/mailRepositories/{encodedPathOfTheRepository}/mails/mailKey?action=reprocess</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>encodedPathOfTheRepository</code> should be the resource id of |
| an existing mail repository. Resource name <code>mailKey</code> should be the key |
| of a mail stored in that repository. Example:</p> |
| </div> |
| <div class="paragraph"> |
| <p>For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/name1?action=reprocess</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Additional query parameters are supported:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>queue</code> allows you to |
| target the mail queue you want to enqueue the mails in. Defaults to |
| <code>spool</code>.</p> |
| </li> |
| <li> |
| <p><code>processor</code> allows you to overwrite the state of the |
| reprocessing mails, and thus select the processors they will start their |
| processing in. Defaults to the <code>state</code> field of each processed email.</p> |
| </li> |
| <li> |
| <p><code>consume</code> (boolean defaulting to <code>true</code>) whether the reprocessing should consume the mail in its originating mail repository. Passing |
| this value to <code>false</code> allows non destructive reprocessing as you keep a copy of the email in the mail repository and can be valuable |
| when debugging.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>While <code>processor</code> being an optional parameter, not specifying it will |
| result reprocessing the mails in their current state |
| (<a href="https://james.apache.org/server/feature-mailetcontainer.html#Processors">see |
| documentation about processors and state</a>). Consequently, only few cases |
| will give a different result, definitively storing them out of the mail |
| repository.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH 'http://ip:port/mailRepositories/var%2Fmail%2Ferror%2F/mails/name1?action=reprocess&processor=transport&queue=spool'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Note that the <code>action</code> query parameter is compulsary and can only take |
| value <code>reprocess</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>404: Could not find that mail repository</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>reprocessing-one</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "mailRepositoryPath":"var/mail/error/", |
| "targetQueue":"spool", |
| "targetProcessor":"transport", |
| "mailKey":"name1" |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_mail_queues"><a class="anchor" href="#_administrating_mail_queues"></a>Administrating mail queues</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_listing_mail_queues"><a class="anchor" href="#_listing_mail_queues"></a>Listing mail queues</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailQueues</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["outgoing","spool"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: The list of mail queues</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_getting_a_mail_queue_details"><a class="anchor" href="#_getting_a_mail_queue_details"></a>Getting a mail queue details</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailQueues/{mailQueueName}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Resource name <code>mailQueueName</code> is the name of a mail queue, this command |
| will return the details of the given mail queue. For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"name":"outgoing","size":0}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| <li> |
| <p>400: Mail queue is not valid</p> |
| </li> |
| <li> |
| <p>404: The mail queue does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_the_mails_of_a_mail_queue"><a class="anchor" href="#_listing_the_mails_of_a_mail_queue"></a>Listing the mails of a mail queue</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailQueues/{mailQueueName}/mails</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Additional URL query parameters:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>limit</code>: Maximum number of mails returned in a single call. Only |
| strictly positive integer values are accepted. Example:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/mailQueues/{mailQueueName}/mails?limit=100</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The answer looks like:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>[{ |
| "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" |
| }]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| <li> |
| <p>400: Mail queue is not valid or limit is invalid</p> |
| </li> |
| <li> |
| <p>404: The mail queue does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_mails_from_a_mail_queue"><a class="anchor" href="#_deleting_mails_from_a_mail_queue"></a>Deleting mails from a mail queue</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mailQueues/{mailQueueName}/mails?sender=senderMailAddress</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This request should have exactly one query parameter from the following |
| list:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>sender: which is a mail address (i.e. <a href="mailto:sender@james.org">sender@james.org</a>)</p> |
| </li> |
| <li> |
| <p>name: which is a string</p> |
| </li> |
| <li> |
| <p>recipient: which is a mail address (i.e. <a href="mailto:recipient@james.org">recipient@james.org</a>)</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The mails from the given mail queue matching the query parameter will be |
| deleted.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Invalid request</p> |
| </li> |
| <li> |
| <p>404: The mail queue does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>delete-mails-from-mail-queue</code> and the following |
| <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "queue":"outgoing", |
| "initialCount":10, |
| "remainingCount": 5, |
| "sender": "sender@james.org", |
| "name": "Java Developer", |
| "recipient: "recipient@james.org" |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_clearing_a_mail_queue"><a class="anchor" href="#_clearing_a_mail_queue"></a>Clearing a mail queue</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/mailQueues/{mailQueueName}/mails</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>All mails from the given mail queue will be deleted.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Invalid request</p> |
| </li> |
| <li> |
| <p>404: The mail queue does not exist</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>clear-mail-queue</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "queue":"outgoing", |
| "initialCount":10, |
| "remainingCount": 0 |
| }</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_flushing_mails_from_a_mail_queue"><a class="anchor" href="#_flushing_mails_from_a_mail_queue"></a>Flushing mails from a mail queue</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPATCH http://ip:port/mailQueues/{mailQueueName}?delayed=true \ |
| -d '{"delayed": false}' \ |
| -H "Content-Type: application/json"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This request should have the query parameter <em>delayed</em> set to <em>true</em>, in |
| order to indicate only delayed mails are affected. The payload should |
| set the <code>delayed</code> field to false inorder to remove the delay. This is |
| the only supported combination, and it performs a flush.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The mails delayed in the given mail queue will be flushed.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success (No content)</p> |
| </li> |
| <li> |
| <p>400: Invalid request</p> |
| </li> |
| <li> |
| <p>404: The mail queue does not exist</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_rabbitmq_republishing_a_mail_queue_from_cassandra"><a class="anchor" href="#_rabbitmq_republishing_a_mail_queue_from_cassandra"></a>RabbitMQ republishing a mail queue from cassandra</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST 'http://ip:port/mailQueues/{mailQueueName}?action=RepublishNotProcessedMails&olderThan=1d'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This method is specific to the distributed flavor of James, which relies |
| on Cassandra 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 <code>mailQueueName</code> queue in RabbitMQ using the |
| information stored in Cassandra.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>olderThan</code> 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: |
| <code>Nunit</code>. <code>N</code> should be strictly positive. <code>unit</code> could be either in the |
| short form (<code>h</code>, <code>d</code>, <code>w</code>, etc.), or in the long form (<code>day</code>, <code>week</code>, |
| <code>month</code>, etc.).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Examples:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>5h</code></p> |
| </li> |
| <li> |
| <p><code>7d</code></p> |
| </li> |
| <li> |
| <p><code>1y</code></p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task created</p> |
| </li> |
| <li> |
| <p>400: Invalid request</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The response body contains the id of the republishing task. |
| <code>{ "taskId": "a650a66a-5984-431e-bdad-f1baad885856" }</code></p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_cassandra_view_of_the_rabbitmq_mailqueue_browse_start_update"><a class="anchor" href="#_cassandra_view_of_the_rabbitmq_mailqueue_browse_start_update"></a>Cassandra view of the RabbitMQ mailQueue: browse start update</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST 'http://ip:port/mailQueues/{mailQueueName}?action=updateBrowseStart</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return a task that updates the browse start of the aforementioned mailQueue, regardless of the configuration.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is an advanced, potentially expensive operation which requires a good understanding of the RabbitMQMailQueue design |
| (<a href="https://github.com/apache/james-project/blob/master/src/adr/0031-distributed-mail-queue.md" class="bare">https://github.com/apache/james-project/blob/master/src/adr/0031-distributed-mail-queue.md</a>). Especially, care needs to |
| be taken to call this at most once per slice (not doing so might be expensive).</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_sending_email_over_webadmin"><a class="anchor" href="#_sending_email_over_webadmin"></a>Sending email over webAdmin</h2> |
| <div class="sectionbody"> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /mail-transfer-service |
| |
| {MIME message}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will send the following email to the recipients specified in the MIME message.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>{MIME message}</code> payload must match <code>message/rfc822</code> format.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_event_dead_letter"><a class="anchor" href="#_event_dead_letter"></a>Event Dead Letter</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_mailbox_listener_groups"><a class="anchor" href="#_listing_mailbox_listener_groups"></a>Listing mailbox listener groups</h3> |
| <div class="paragraph"> |
| <p>This endpoint allows discovering the list of mailbox listener groups.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/events/deadLetter/groups</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return a list of group names that can be further used to interact |
| with the dead letter API:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["org.apache.james.mailbox.events.EventBusTestFixture$GroupA", "org.apache.james.mailbox.events.GenericGroup-abc"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success. A list of group names is returned.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_failed_events"><a class="anchor" href="#_listing_failed_events"></a>Listing failed events</h3> |
| <div class="paragraph"> |
| <p>This endpoint allows listing failed events for a given group:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return a list of insertionIds:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>["6e0dd59d-660e-4d9b-b22f-0354479f47b4", "58a8f59d-660e-4d9b-b22f-0354486322a2"]</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success. A list of insertion ids is returned.</p> |
| </li> |
| <li> |
| <p>400: Invalid group name</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_getting_event_details"><a class="anchor" href="#_getting_event_details"></a>Getting event details</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA/6e0dd59d-660e-4d9b-b22f-0354479f47b4</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the full JSON associated with this event.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success. A JSON representing this event is returned.</p> |
| </li> |
| <li> |
| <p>400: Invalid group name or <code>insertionId</code></p> |
| </li> |
| <li> |
| <p>404: No event with this <code>insertionId</code></p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_an_event"><a class="anchor" href="#_deleting_an_event"></a>Deleting an event</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA/6e0dd59d-660e-4d9b-b22f-0354479f47b4</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will delete this event.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success</p> |
| </li> |
| <li> |
| <p>400: Invalid group name or <code>insertionId</code></p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_deleting_all_events_of_a_group"><a class="anchor" href="#_deleting_all_events_of_a_group"></a>Deleting all events of a group</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will delete all events of this group.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: Success</p> |
| </li> |
| <li> |
| <p>400: Invalid group name</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_redeliver_all_events"><a class="anchor" href="#_redeliver_all_events"></a>Redeliver all events</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/events/deadLetter?action=reDeliver</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Additional query parameters are supported:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>limit</code> (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</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/events/deadLetter?action=reDeliver&limit=10</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will create a task that will attempt to redeliver all events stored in |
| <code>Event Dead Letter''. If successful, redelivered events will then be |
| removed from </code>Dead Letter''.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: the taskId of the created task</p> |
| </li> |
| <li> |
| <p>400: Invalid action argument</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_redeliver_group_events"><a class="anchor" href="#_redeliver_group_events"></a>Redeliver group events</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA?action=reDeliver</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will create a task that will attempt to redeliver all events of a |
| particular group stored in <code>Event Dead Letter''. If successful, |
| redelivered events will then be removed from </code>Dead Letter''.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Additional query parameters are supported:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>limit</code> (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</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>For instance:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA?action=reDeliver&limit=10</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: the taskId of the created task</p> |
| </li> |
| <li> |
| <p>400: Invalid group name or action argument</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_redeliver_a_single_event"><a class="anchor" href="#_redeliver_a_single_event"></a>Redeliver a single event</h3> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/events/deadLetter/groups/org.apache.james.mailbox.events.EventBusTestFixture$GroupA/6e0dd59d-660e-4d9b-b22f-0354479f47b4?action=reDeliver</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will create a task that will attempt to redeliver a single event of a |
| particular group stored in <code>Event Dead Letter''. If successful, |
| redelivered event will then be removed from </code>Dead Letter''.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: the taskId of the created task</p> |
| </li> |
| <li> |
| <p>400: Invalid group name, insertion id or action argument</p> |
| </li> |
| <li> |
| <p>404: No event with this insertionId</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_cassandra_extra_operations"><a class="anchor" href="#_cassandra_extra_operations"></a>Cassandra extra operations</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Some webadmin features to manage some extra operations on Cassandra |
| tables, like solving inconsistencies on projection tables. Such |
| inconsistencies can be for example created by a fail of the DAO to add a |
| mapping into |
| ’mappings_sources`, while it was successful regarding the`rrt` table.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_operations_on_mappings_sources"><a class="anchor" href="#_operations_on_mappings_sources"></a>Operations on mappings sources</h3> |
| <div class="paragraph"> |
| <p>You can do a series of action on <code>mappings_sources</code> projection table :</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /cassandra/mappings?action={action}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return the taskId corresponding to the related task. Actions |
| supported so far are :</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>SolveInconsistencies : cleans up first all the mappings in |
| <code>mappings_sources</code> index and then repopulate it correctly. In the |
| meantime, listing sources of a mapping might create temporary |
| inconsistencies during the process.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>For example :</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST /cassandra/mappings?action=SolveInconsistencies</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes :</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: the taskId of the created task</p> |
| </li> |
| <li> |
| <p>400: Invalid action argument for performing operation on mappings data</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_cassandra_schema_upgrades"><a class="anchor" href="#_cassandra_schema_upgrades"></a>Cassandra Schema upgrades</h3> |
| <div class="paragraph"> |
| <p>Cassandra upgrades implies the creation of a new table. Thus restarting |
| James is needed, as new tables are created on restart.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Once done, we ship code that tries to read from new tables, and if not |
| possible backs up to old tables. You can thus safely run without running |
| additional migrations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>On the fly migration can be enabled. However, one might want to force |
| the migration in a controlled fashion, and update automatically current |
| schema version used (assess in the database old versions is no more |
| used, as the corresponding tables are empty). Note that this process is |
| safe: we ensure the service is not running concurrently on this James |
| instance, that it does not bump version upon partial failures, that race |
| condition in version upgrades will be idempotent, etc…</p> |
| </div> |
| <div class="paragraph"> |
| <p>These schema updates can be triggered by webadmin using the Cassandra |
| backend.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Note that currently the progress can be tracked by logs.</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="#<em>retrieving_current_cassandra_schema_version</em>">Retrieving current |
| Cassandra schema version</a></p> |
| </li> |
| <li> |
| <p><a href="#<em>retrieving_latest_available_cassandra_schema_version</em>">Retrieving |
| latest available Cassandra schema version</a></p> |
| </li> |
| <li> |
| <p><a href="#<em>upgrading_to_a_specific_version</em>">Upgrading to a specific version</a></p> |
| </li> |
| <li> |
| <p><a href="#<em>upgrading_to_the_latest_version</em>">Upgrading to the latest version</a></p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect3"> |
| <h4 id="_retrieving_current_cassandra_schema_version"><a class="anchor" href="#_retrieving_current_cassandra_schema_version"></a>Retrieving current Cassandra schema version</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/cassandra/version</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"version": 2}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where the number corresponds to the current schema version of the |
| database you are using.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_retrieving_latest_available_cassandra_schema_version"><a class="anchor" href="#_retrieving_latest_available_cassandra_schema_version"></a>Retrieving latest available Cassandra schema version</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/cassandra/version/latest</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will return:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"version": 3}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Where the number corresponds to the latest available schema version of |
| the database you are using. This means you can be migrating to this |
| schema version.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_upgrading_to_a_specific_version"><a class="anchor" href="#_upgrading_to_a_specific_version"></a>Upgrading to a specific version</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST -H "Content-Type: application/json http://ip:port/cassandra/version/upgrade -d '3'</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule the run of the migrations you need to reach schema version |
| 3.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success. The scheduled task <code>taskId</code> is returned.</p> |
| </li> |
| <li> |
| <p>400: The version is invalid. The version should be a strictly positive |
| number.</p> |
| </li> |
| <li> |
| <p>410: Error while planning this migration. This resource is gone away. |
| Reason is mentionned in the body.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note that several calls to this endpoint will be run in a sequential |
| pattern.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the server restarts during the migration, the migration is silently |
| aborted.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>cassandra-migration</code> |
| and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"targetVersion":3}</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_upgrading_to_the_latest_version"><a class="anchor" href="#_upgrading_to_the_latest_version"></a>Upgrading to the latest version</h4> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/cassandra/version/upgrade/latest</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will schedule the run of the migrations you need to reach the latest |
| schema version.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: Success. The scheduled task <code>taskId</code> is returned.</p> |
| </li> |
| <li> |
| <p>410: Error while planning this migration. This resource is gone away. |
| Reason is mentionned in the body.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Note that several calls to this endpoint will be run in a sequential |
| pattern.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If the server restarts during the migration, the migration is silently |
| aborted.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>cassandra-migration</code> |
| and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"toVersion":2}</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_correcting_ghost_mailbox"><a class="anchor" href="#_correcting_ghost_mailbox"></a>Correcting ghost mailbox</h3> |
| <div class="paragraph"> |
| <p>This is a temporary workaround for the <strong>Ghost mailbox</strong> bug encountered |
| using the Cassandra backend, as described in MAILBOX-322.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can use the mailbox merging feature in order to merge the old |
| ``ghosted'' mailbox with the new one.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/cassandra/mailbox/merging \ |
| -d '{"mergeOrigin":"{id1}", "mergeDestination":"{id2}"}' \ |
| -H "Content-Type: application/json"</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Will scedule a task for :</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Delete references to <code>id1</code> mailbox</p> |
| </li> |
| <li> |
| <p>Move it’s messages into <code>id2</code> mailbox</p> |
| </li> |
| <li> |
| <p>Union the rights of both mailboxes</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task generation succeeded. Corresponding task id is returned.</p> |
| </li> |
| <li> |
| <p>400: Unable to parse the body.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type <code>mailbox-merging</code> and |
| the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "oldMailboxId":"5641376-02ed-47bd-bcc7-76ff6262d92a", |
| "newMailboxId":"4555159-52ae-895f-ccb7-586a4412fb50", |
| "totalMessageCount": 1, |
| "messageMovedCount": 1, |
| "messageFailedCount": 0 |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_deleted_messages_vault"><a class="anchor" href="#_deleted_messages_vault"></a>Deleted Messages Vault</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The `Deleted Message Vault plugin' allows you to keep users deleted |
| messages during a given retention time. This set of routes allow you to |
| <em>restore</em> users deleted messages or export them in an archive.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To move deleted messages in the vault, you need to specifically |
| configure the DeletedMessageVault PreDeletionHook.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_restore_deleted_messages"><a class="anchor" href="#_restore_deleted_messages"></a>Restore Deleted Messages</h3> |
| <div class="paragraph"> |
| <p>Deleted messages of a specific user can be restored by calling the |
| following endpoint:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>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" |
| } |
| ] |
| };</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The requested Json body is made from a list of criterion objects which |
| have the following structure:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "fieldName": "supportedFieldName", |
| "operator": "supportedOperator", |
| "value": "A plain string representing the matching value of the corresponding field" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Deleted Messages which are matched with the <strong>all</strong> criterion in the query |
| body will be restored. Here are a list of supported fieldName for the |
| restoring:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>subject: represents for deleted message <code>subject</code> field matching. |
| Supports below string operators:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>contains</p> |
| </li> |
| <li> |
| <p>containsIgnoreCase</p> |
| </li> |
| <li> |
| <p>equals</p> |
| </li> |
| <li> |
| <p>equalsIgnoreCase</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>deliveryDate: represents for deleted message <code>deliveryDate</code> field |
| matching. Tested value should follow the right date time with zone |
| offset format (ISO-8601) like <code>2008-09-15T15:53:00+05:00</code> or |
| <code>2008-09-15T15:53:00Z</code> Supports below date time operators:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>beforeOrEquals: is the deleted message’s <code>deliveryDate</code> before or |
| equals the time of tested value.</p> |
| </li> |
| <li> |
| <p>afterOrEquals: is the deleted message’s <code>deliveryDate</code> after or |
| equals the time of tested value</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>deletionDate: represents for deleted message <code>deletionDate</code> field |
| matching. Tested value & Supports operators: similar to <code>deliveryDate</code></p> |
| </li> |
| <li> |
| <p>sender: represents for deleted message <code>sender</code> field matching. Tested |
| value should be a valid mail address. Supports mail address operator:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>equals: does the tested sender equal to the sender of the tested |
| deleted message ?<br></p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>recipients: represents for deleted message <code>recipients</code> field |
| matching. Tested value should be a valid mail address. Supports list |
| mail address operator:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>contains: does the tested deleted message’s recipients contain tested |
| recipient ?</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>hasAttachment: represents for deleted message <code>hasAttachment</code> field |
| matching. Tested value could be <code>false</code> or <code>true</code>. Supports boolean |
| operator:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>equals: does the tested deleted message’s hasAttachment property |
| equal to the tested hasAttachment value?</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>originMailboxes: represents for deleted message <code>originMailboxes</code> |
| field matching. Tested value is a string serialized of mailbox id. |
| Supports list mailbox id operators:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>contains: does the tested deleted message’s originMailbox ids contain |
| tested mailbox id ?</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Note</strong>:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Query parameter <code>action</code> is required and should have the value |
| <code>restore</code> to represent the restoring feature. Otherwise, a bad request |
| response will be returned</p> |
| </li> |
| <li> |
| <p>Query parameter <code>action</code> is case sensitive</p> |
| </li> |
| <li> |
| <p>fieldName & operator passed to the routes are case sensitive</p> |
| </li> |
| <li> |
| <p>Currently, we only support query combinator <code>and</code> value, otherwise, |
| requests will be rejected</p> |
| </li> |
| <li> |
| <p>If you only want to restore by only one criterion, the json body could |
| be simplified to a single criterion:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "fieldName": "subject", |
| "operator": "containsIgnoreCase", |
| "value": "Apache James" |
| }</pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>For restoring all deleted messages, passing a query json with an empty |
| criterion list to represent <code>matching all deleted messages</code>:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "combinator": "and", |
| "criteria": [] |
| }</pre> |
| </div> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>For limiting the number of restored messages, you can use the <code>limit</code> query property:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "combinator": "and", |
| "limit": 99 |
| "criteria": [] |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Warning</strong>: Current web-admin uses <code>US</code> locale as the default. Therefore, |
| there might be some conflicts when using String <code>containsIgnoreCase</code> |
| comparators to apply on the String data of other special locales stored |
| in the Vault. More details at |
| <a href="https://issues.apache.org/jira/browse/MAILBOX-384">JIRA</a></p> |
| </div> |
| <div class="paragraph"> |
| <p>Response code:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task for restoring deleted has been created</p> |
| </li> |
| <li> |
| <p>400: Bad request:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>action query param is not present</p> |
| </li> |
| <li> |
| <p>action query param is not a valid action</p> |
| </li> |
| <li> |
| <p>user parameter is invalid</p> |
| </li> |
| <li> |
| <p>can not parse the JSON body</p> |
| </li> |
| <li> |
| <p>Json query object contains unsupported operator, fieldName</p> |
| </li> |
| <li> |
| <p>Json query object values violate parsing rules</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>404: User not found</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>deleted-messages-restore</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "successfulRestoreCount": 47, |
| "errorRestoreCount": 0, |
| "user": "userToRestore@domain.ext" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>while:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>successfulRestoreCount: number of restored messages</p> |
| </li> |
| <li> |
| <p>errorRestoreCount: number of messages that failed to restore</p> |
| </li> |
| <li> |
| <p>user: owner of deleted messages need to restore</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_export_deleted_messages"><a class="anchor" href="#_export_deleted_messages"></a>Export Deleted Messages</h3> |
| <div class="paragraph"> |
| <p>Retrieve deleted messages matched with requested query from an user then |
| share the content to a targeted mail address (exportTo)</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>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</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Note</strong>: Json query passing into the body follows the same rules & |
| restrictions like in <a href="#_restore_deleted_messages">Restore Deleted |
| Messages</a></p> |
| </div> |
| <div class="paragraph"> |
| <p>Response code:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task for exporting has been created</p> |
| </li> |
| <li> |
| <p>400: Bad request:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>exportTo query param is not present</p> |
| </li> |
| <li> |
| <p>exportTo query param is not a valid mail address</p> |
| </li> |
| <li> |
| <p>action query param is not present</p> |
| </li> |
| <li> |
| <p>action query param is not a valid action</p> |
| </li> |
| <li> |
| <p>user parameter is invalid</p> |
| </li> |
| <li> |
| <p>can not parse the JSON body</p> |
| </li> |
| <li> |
| <p>Json query object contains unsupported operator, fieldName</p> |
| </li> |
| <li> |
| <p>Json query object values violate parsing rules</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>404: User not found</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>deleted-messages-export</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "userExportFrom": "userToRestore@domain.ext", |
| "exportTo": "userReceiving@domain.ext", |
| "totalExportedMessages": 1432 |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>while:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>userExportFrom: export deleted messages from this user</p> |
| </li> |
| <li> |
| <p>exportTo: content of deleted messages have been shared to this mail |
| address</p> |
| </li> |
| <li> |
| <p>totalExportedMessages: number of deleted messages match with |
| json query, then being shared to sharee.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_purge_deleted_messages"><a class="anchor" href="#_purge_deleted_messages"></a>Purge Deleted Messages</h3> |
| <div class="paragraph"> |
| <p>You can overwrite `retentionPeriod' configuration in |
| `deletedMessageVault' configuration file or use the default value of 1 |
| year.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Purge all deleted messages older than the configured `retentionPeriod'</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/deletedMessages?scope=expired</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response code:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task for purging has been created</p> |
| </li> |
| <li> |
| <p>400: Bad request:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>action query param is not present</p> |
| </li> |
| <li> |
| <p>action query param is not a valid action</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>You may want to call this endpoint on a regular basis.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_permanently_remove_deleted_message"><a class="anchor" href="#_permanently_remove_deleted_message"></a>Permanently Remove Deleted Message</h3> |
| <div class="paragraph"> |
| <p>Delete a Deleted Message with <code>MessageId</code></p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/deletedMessages/users/user@domain.ext/messages/3294a976-ce63-491e-bd52-1b6f465ed7a2</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><a href="#_endpoints_returning_a_task">More details about endpoints returning |
| a task</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Response code:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>201: Task for deleting message has been created</p> |
| </li> |
| <li> |
| <p>400: Bad request:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>user parameter is invalid</p> |
| </li> |
| <li> |
| <p>messageId parameter is invalid</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| <li> |
| <p>404: User not found</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The scheduled task will have the following type |
| <code>deleted-messages-delete</code> and the following <code>additionalInformation</code>:</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre> { |
| "userName": "user@domain.ext", |
| "messageId": "3294a976-ce63-491e-bd52-1b6f465ed7a2" |
| }</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>while: - user: delete deleted messages from this user - deleteMessageId: |
| messageId of deleted messages will be delete</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_administrating_dlp_configuration"><a class="anchor" href="#_administrating_dlp_configuration"></a>Administrating DLP Configuration</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>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 <code>senderDomain</code> basis.</p> |
| </div> |
| <div class="paragraph"> |
| <p><code>senderDomain</code> is domain of the sender of incoming emails, for example: |
| <code>apache.org</code>, <code>james.org</code>,… Each <code>senderDomain</code> correspond to a distinct |
| DLP configuration.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_list_dlp_configuration_by_sender_domain"><a class="anchor" href="#_list_dlp_configuration_by_sender_domain"></a>List DLP configuration by sender domain</h3> |
| <div class="paragraph"> |
| <p>Retrieve a DLP configuration for corresponding <code>senderDomain</code>, a |
| configuration contains list of configuration items</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/dlp/rules/{senderDomain}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: A list of dlp configuration items is returned</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>senderDomain</code> or payload in request</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This is an example of returned body. The rules field is a list of rules |
| as described below.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"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 |
| } |
| ]}</pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_store_dlp_configuration_by_sender_domain"><a class="anchor" href="#_store_dlp_configuration_by_sender_domain"></a>Store DLP configuration by sender domain</h3> |
| <div class="paragraph"> |
| <p>Store a DLP configuration for corresponding <code>senderDomain</code>, if any item |
| of DLP configuration in the request is stored before, it will not be |
| stored anymore</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPUT http://ip:port/dlp/rules/{senderDomain}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The body can contain a list of DLP configuration items formed by those |
| fields: - <code>id</code>(String) is mandatory, unique identifier of the |
| configuration item - <code>expression</code>(String) is mandatory, regular |
| expression to match contents of targets - <code>explanation</code>(String) is |
| optional, description of the configuration item - |
| <code>targetsSender</code>(boolean) is optional and defaults to false. If true, |
| <code>expression</code> will be applied to Sender and to From headers of the mail - |
| <code>targetsContent</code>(boolean) is optional and defaults to false. If true, |
| <code>expression</code> will be applied to Subject headers and textual bodies |
| (text/plain and text/html) of the mail - <code>targetsRecipients</code>(boolean) is |
| optional and defaults to false. If true, <code>expression</code> will be applied to |
| recipients of the mail</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is an example of returned body. The rules field is a list of rules |
| as described below.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{"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 |
| } |
| ]}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: List of dlp configuration items is stored</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>senderDomain</code> or payload in request</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_remove_dlp_configuration_by_sender_domain"><a class="anchor" href="#_remove_dlp_configuration_by_sender_domain"></a>Remove DLP configuration by sender domain</h3> |
| <div class="paragraph"> |
| <p>Remove a DLP configuration for corresponding <code>senderDomain</code></p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XDELETE http://ip:port/dlp/rules/{senderDomain}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: DLP configuration is removed</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>senderDomain</code> or payload in request</p> |
| </li> |
| <li> |
| <p>404: The domain does not exist.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_fetch_a_dlp_configuration_item_by_sender_domain_and_rule_id"><a class="anchor" href="#_fetch_a_dlp_configuration_item_by_sender_domain_and_rule_id"></a>Fetch a DLP configuration item by sender domain and rule id</h3> |
| <div class="paragraph"> |
| <p>Retrieve a DLP configuration rule for corresponding <code>senderDomain</code> and a |
| <code>ruleId</code></p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XGET http://ip:port/dlp/rules/{senderDomain}/rules/{ruleId}</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Response codes:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>200: A dlp configuration item is returned</p> |
| </li> |
| <li> |
| <p>400: Invalid <code>senderDomain</code> or payload in request</p> |
| </li> |
| <li> |
| <p>404: The domain and/or the rule does not exist.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>This is an example of returned body.</p> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>{ |
| "id": "1", |
| "expression": "james.org", |
| "explanation": "Find senders or recipients containing james[any char]org", |
| "targetsSender": true, |
| "targetsRecipients": true, |
| "targetsContent": false |
| }</pre> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_reloading_server_certificates"><a class="anchor" href="#_reloading_server_certificates"></a>Reloading server certificates</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Certificates for TCP based protocols (IMAP, SMTP, POP3, LMTP and ManageSieve) can be updated at |
| runtime, without service interuption and without closing existing connections.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In order to do so:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Generate / retrieve your cryptographic materials and replace the ones specified in James configuration.</p> |
| </li> |
| <li> |
| <p>Then call the following endpoint:</p> |
| </li> |
| </ul> |
| </div> |
| <div class="literalblock"> |
| <div class="content"> |
| <pre>curl -XPOST http://ip:port/servers?reload-certificate</pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Optional query parameters:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><code>port</code>: positive integer (valid port number). Only reload certificates for the specific port.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>Return code:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>204: the certificate is reloaded</p> |
| </li> |
| <li> |
| <p>400: Invalid request.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </article> |
| </div> |
| </main> |
| </div> |
| <footer class="footer"> |
| <p>This page was built using the Antora default UI.</p> |
| <p>The source code for this UI is licensed under the terms of the MPL-2.0 license.</p> |
| </footer> |
| <script id="site-script" src="../../../_/js/site.js" data-ui-root-path="../../../_"></script> |
| <script async src="../../../_/js/vendor/highlight.js"></script> |
| </body> |
| </html> |