blob: 0527a3d6c144443a3cc8c8b458f14bf016da1de9 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Distributed James Server &mdash; 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-project" data-version="3.6.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 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="../../../concepts/index.html">Concepts</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../concepts/user/index.html">User Model</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../../concepts/mail/index.html">Emails</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="#mail/messages/index.adoc">mail/messages/index.adoc</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="#mail/messages/imf.adoc">mail/messages/imf.adoc</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="#mail/messages/mime.adoc">mail/messages/mime.adoc</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../../concepts/protocols/index.html">Protocols</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/protocols/smtp.html">SMTP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/protocols/pop.html">POP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/protocols/imap.html">IMAP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/protocols/jmap.html">JMAP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/protocols/esmtp.html">ESMTP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/protocols/lmtp.html">LMTP</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../../concepts/storage/index.html">Storage</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/storage/mailbox.html">Mailboxes</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../../concepts/storage/users.html">Users</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../concepts/processing/index.html">Processing</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../concepts/configuration.html">Configuration</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../concepts/glossary.html">Glossary</a>
</li>
</ul>
</li>
</ul>
</li>
<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">Servers</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../demo.html">Demo</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../5-minute-demo.html">Short Demo</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../15-minute-demo.html">Long Demo</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../basic/index.html">Basic</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../basic/context.html">Context</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../basic/objectives.html">Objectives</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../basic/concepts.html">Concepts</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../basic/architecture.html">Architecture</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../basic/conf/index.html">Configuration</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../basic/help.html">Help</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../extendable.html">Extendable</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../distributed.html">Distributed</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../objectives.html">Objectives and motivation</a>
</li>
<li class="nav-item" data-depth="3">
<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="4">
<a class="nav-link" href="../architecture/consistency-model.html">Consistency Model</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../architecture/specialized-instances.html">Specialized instances</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../run.html">Run</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../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="../configure/index.html">Configuration</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<span class="nav-text">Protocols</span>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/imap.html">imapserver.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/jmap.html">jmap.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/jmx.html">jmx.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/smtp.html">smtpserver.xml &amp; lmtpserver.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/smtp-hooks.html">Packaged SMTP hooks</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/pop3.html">pop3server.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/webadmin.html">webadmin.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/ssl.html">SSL &amp; TLS</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<span class="nav-text">Storage dependencies</span>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/blobstore.html">blobstore.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/cassandra.html">cassandra.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/elasticsearch.html">elasticsearch.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/rabbitmq.html">rabbitmq.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/tika.html">tika.properties</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<span class="nav-text">Core components</span>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/batchsizes.html">batchsizes.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/dns.html">dnsservice.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/domainlist.html">domainlist.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/healthcheck.html">healthcheck.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/mailetcontainer.html">mailetcontainer.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/mailets.html">Packaged Mailets</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/matchers.html">Packaged Matchers</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/mailrepositorystore.html">mailrepositorystore.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/recipientrewritetable.html">recipientrewritetable.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/usersrepository.html">usersrepository.xml</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<span class="nav-text">Extensions</span>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/vault.html">deletedMessageVault.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/extensions.html">extensions.properties</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/listeners.html">listeners.xml</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/spam.html">Anti-Spam setup</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/remote-delivery-error-handling.html">About RemoteDelivery error handling</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/collecting-contacts.html">Contact collection</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/collecting-events.html">Event collection</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../configure/dsn.html">ESMTP DSN support</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<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="4">
<a class="nav-link" href="guide.html">Operator guide</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="logging.html">Logging</a>
</li>
<li class="nav-item is-current-page" data-depth="4">
<a class="nav-link" href="webadmin.html">WebAdmin REST administration API</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="metrics.html">Metrics</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="migrating.html">Migrating existing data</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="cli.html">Command Line Interface</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="cassandra-migration.html">Cassandra migration</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<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="4">
<a class="nav-link" href="../extending/mail-processing.html">Custom mail processing components</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../extending/mailbox-listeners.html">Custom Mailbox Listeners</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../extending/smtp-hooks.html">Custom SMTP hooks</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../extending/webadmin-routes.html">Custom WebAdmin routes</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../test.html">Test</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="0">
<ul class="nav-list">
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../../customization/index.html">Customization</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="0">
<ul class="nav-list">
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../../development/index.html">Developer Guide</a>
</li>
</ul>
</li>
<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="../../../community/index.html">Community</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/mailing-lists.html">Mailing lists</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/contributing.html">Contributing</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/guidelines.html">Guidelines</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/download.html">Download releases</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/website.html">Building and publishing the website</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/release.html">Creating an official Apache James release</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../../community/support.html">Professional support</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Apache Software Foundation</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/">ASF</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/foundation/getinvolved.html">Get involved</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/foundation/faq.html">FAQ</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/licenses/">Licenses</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/security/">Security</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="https://www.apache.org/foundation/thanks.html">Thanks</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 Server</span>
<span class="version">3.6.0 Snapshot</span>
</div>
<ul class="components">
<li class="component">
<div class="title"><a href="../../../../../james-distributed-app/3.8.1/index.html">Apache James Distributed Server</a></div>
<ul class="versions">
<li class="version is-latest">
<a href="../../../../../james-distributed-app/3.8.1/index.html">3.8.1 SNAPSHOT</a>
</li>
</ul>
</li>
<li class="component is-current">
<div class="title"><a href="../../../../3.8.1/index.html">Apache James Server</a></div>
<ul class="versions">
<li class="version is-latest">
<a href="../../../../3.8.1/index.html">3.8.1 SNAPSHOT</a>
</li>
<li class="version is-current">
<a href="../../../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 Server</a></li>
<li><a href="../../index.html">Servers</a></li>
<li><a href="../../distributed.html">Distributed</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="page-versions">
<button class="version-menu-toggle" title="Show other versions of page">3.6.0 Snapshot</button>
<div class="version-menu">
<a class="version is-missing" href="../../../../3.8.1/index.html">3.8.1 SNAPSHOT</a>
<a class="version is-current" href="webadmin.html">3.6.0 Snapshot</a>
</div>
</div>
<div class="edit-this-page"><a href="https://github.com/apache/james-project/blob/james-project-3.6.0/docs/modules/servers/pages/distributed/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 &mdash; 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 &amp; 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: &lt;error_code&gt;,
type: &lt;error_type&gt;,
message: &lt;the_error_message&gt;
cause: &lt;the_detail_message_from_throwable&gt;
}</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>ElasticSearch Backend</strong>: ElasticSearch 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>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 anwered with a 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 usefull for testing purpose but still can
serve real-life scenari.</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.</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>
<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>
</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="#distributed/confgure/usersrepository.adoc" class="xref unresolved">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&#8217;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&#8217;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="_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>
</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 &amp; 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&amp;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="_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&amp;messagesPerSecond=200&amp;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&amp;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&amp;reIndexFailedMessagesOf=bbdb69c9-082a-44b0-a85a-6e33e74287a5&amp;messagesPerSecond=200&amp;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>
</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&amp;messagesPerSecond=200&amp;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 &amp; 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&amp;messagesPerSecond=200&amp;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>
</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</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</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</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</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&amp;messagesPerSecond=200&amp;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="_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&amp;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&amp;maxOccupationRatio=0.99&amp;limit=100&amp;offset=200&amp;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>Example:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>curl -XPOST /quota/users?task=RecomputeCurrentQuotas&amp;usersPerSecond=20</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",
"processedQuotaRoots": 3,
"failedQuotaRoots": ["#private&amp;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
desactivated.</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
desactivated.</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
desactivated.</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
desactivated.</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
desactivated.</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_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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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 ommitted.</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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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: The alias source exists as an user already</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 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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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="#distributed/architecture.adoc#_recipient_rewrite_tables" class="xref unresolved">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&amp;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 &lt;em&gt;body&lt;/em&gt;!!",
"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: - <code>queue</code> allows you to
target the mail queue you want to enqueue the mails in. Defaults to
<code>spool</code>. - <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>
</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&amp;processor=transport&amp;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: - <code>queue</code> allows you to
target the mail queue you want to enqueue the mails in. Defaults to
<code>spool</code>. - <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>
</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&amp;processor=transport&amp;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&amp;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>
</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="_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>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</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><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="#Retrieving_current_Cassandra_schema_version">Retrieving current
Cassandra schema version</a></p>
</li>
<li>
<p><a href="#Retrieving_latest_available_Cassandra_schema_version">Retrieving
latest available Cassandra schema version</a></p>
</li>
<li>
<p><a href="#Upgrading_to_a_specific_version">Upgrading to a specific version</a></p>
</li>
<li>
<p><a href="#Upgrading_to_the_latest_version">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 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 &amp; 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 &amp; 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="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&amp;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 &amp;
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>
</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>