<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Alerts, the audit trail, syslog and the journal, and per-domain reports]]></title><description><![CDATA[<p dir="auto"><em>Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) moves the Control Panel's Audit trail page, with journaling and eDiscovery, into a new Compliance group, and the alerts' settings, the outbound webhooks and the SNMP agent onto its Monitoring &amp; alerts page (API &amp; monitoring until 6.3.6; 6.3.5 and 6.3.6 had them on Logging); Ctrl+K takes an old title or route to its page. It also fixes the SMTP log, whose lines the syslog sink copies, which wrote some credentials in the clear with SMTP logging on, in every version from 6.0.0 to 6.3.6 (work item #95). See <a href="/topic/28277">the 6.3.7 announcement</a>.</em></p>
<p dir="auto">This topic covers four things 6.3.4 adds for being told what the server is doing and who changed it: the alerts, the audit trail, the syslog sink (or the systemd journal on Linux) and the per-domain reports, with a paragraph on following one connection live. The one thing to know first: <strong>after the upgrade to 6.3.4 the audit trail and the alerts are on</strong>, with seven of the eleven conditions enabled, but <strong>nothing is mailed until <code>AlertRecipient</code> and <code>AlertSenderAddress</code> are set</strong>.</p>
<h3><a class="anchor-offset" name="what-6.3.4-switches-on-without-a-switch"></a>What 6.3.4 switches on without a switch</h3>
<p dir="auto">From the CHANGELOG's list of what changes on upgrade: the audit trail is on (schema 6043), and keeps every row until a retention is set. Compromised-account detection starts in <strong>watch mode</strong> (schema 6071): it raises <code>account.compromised</code> but holds nothing until <code>compromise_detection_mode</code> is set to <code>enforce</code>. The reputation watch, which raises <code>reputation.listed</code>, is on in a new installation and off after an upgrade.</p>
<h3><a class="anchor-offset" name="alerts"></a>Alerts</h3>
<p dir="auto">A <strong>condition</strong> is a row in <code>hm_alertrules</code> (on or off, threshold, mail or webhook or both, cool-down, at once or in the digest); an <strong>event</strong> is a row in <code>hm_alertevents</code>. <strong>Delivery</strong> is <code>AlertTask</code>, once a minute, and nothing else sends, so an alert about the delivery queue is never itself submitted into the stuck queue.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Condition</th>
<th>On as shipped</th>
<th>Raised by</th>
<th>Threshold</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>backup.failed</code></td>
<td>yes</td>
<td>A backup that failed, and a scheduled backup that could not run. Sent at once</td>
<td>—</td>
</tr>
<tr>
<td><code>certificate.expiring</code></td>
<td>yes</td>
<td>The notAfter of every configured certificate, read once a minute</td>
<td>7 days</td>
</tr>
<tr>
<td><code>disk.low</code></td>
<td>no</td>
<td>The free-space warning band, and again below the floor; cleared on recovery</td>
<td>—</td>
</tr>
<tr>
<td><code>queue.stalled</code></td>
<td>no</td>
<td>A work queue whose every thread has been in the same task past <code>AsyncQueueStallThreshold</code></td>
<td>—</td>
</tr>
<tr>
<td><code>autoban.storm</code></td>
<td>no</td>
<td>Auto-bans in the last hour</td>
<td>25</td>
</tr>
<tr>
<td><code>minidump.written</code></td>
<td>no</td>
<td>A crash dump newer than the last one recorded, in the log directory</td>
<td>—</td>
</tr>
<tr>
<td><code>complaints.rate.high</code></td>
<td>yes</td>
<td>A hosted domain's complaint rate over the feedback loops' seven-day window; inert while complaint processing is off, and a domain that sent fewer than 100 messages is not judged</td>
<td>1,000 per million</td>
</tr>
<tr>
<td><code>dkim.rotation.stalled</code></td>
<td>yes</td>
<td>A rotation whose next key's record has not been seen for the threshold, or a running rotation whose last move failed</td>
<td>7 days</td>
</tr>
<tr>
<td><code>account.compromised</code></td>
<td>yes</td>
<td>Compromised-account detection at submission, one event per account per hour; in <code>watch</code> mode the detail says what enforcing would have done</td>
<td>—</td>
</tr>
<tr>
<td><code>account.password-reset</code></td>
<td>yes</td>
<td>A password reset completed through an account's confirmed recovery address; no cool-down and no digest</td>
<td>—</td>
</tr>
<tr>
<td><code>reputation.listed</code></td>
<td>yes</td>
<td>The reputation watch's stored rows; sent at once, and a check that was refused or timed out does not clear it</td>
<td>—</td>
</tr>
</tbody>
</table>
<p dir="auto">The four that are off are noisy on a healthy server.</p>
<p dir="auto"><strong>The settings.</strong> All nine are rows of <code>hm_settings</code>, none an <code>hMailServer.ini</code> key. They are in the server group of <code>GET</code>/<code>PUT /api/v1/settings</code>, on the Deck's Settings page, and on Windows over COM through <code>Settings</code>. The CHANGELOG and <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/AlertsAndAuditTrail.md" rel="nofollow ugc">AlertsAndAuditTrail.md</a> spell some in their <code>hm_settings</code> form (<code>AlertRecipient</code>, <code>AlertSenderAddress</code> and so on); the REST keys are these.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>REST key</th>
<th>Default</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>alerts_enabled</code></td>
<td>on</td>
<td>The master switch</td>
</tr>
<tr>
<td><code>alert_recipient</code></td>
<td>empty</td>
<td>Where alerts and the digest go; a rule can name an <code>address</code> of its own instead</td>
</tr>
<tr>
<td><code>alert_sender_address</code></td>
<td>empty</td>
<td>What they are sent from; a rule with no sender sends nothing</td>
</tr>
<tr>
<td><code>alert_digest_enabled</code></td>
<td>on</td>
<td>Whether rules marked for the digest wait for it</td>
</tr>
<tr>
<td><code>alert_digest_hour</code></td>
<td>7</td>
<td>The hour, <strong>UTC</strong>, the digest goes out; a digest with nothing in it is not sent</td>
</tr>
<tr>
<td><code>alert_max_per_hour</code></td>
<td>20</td>
<td>Past this many single alerts in an hour, everything goes into the digest</td>
</tr>
<tr>
<td><code>alert_webhook_max_attempts</code></td>
<td>5</td>
<td>Webhook attempts before an event is dead-lettered (1 to 20)</td>
</tr>
<tr>
<td><code>audit_trail_enabled</code></td>
<td>on</td>
<td>Whether administrative changes are recorded</td>
</tr>
<tr>
<td><code>audit_retention_days</code></td>
<td>0</td>
<td>Days of trail to keep; 0 keeps everything</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>Nothing may flap.</strong> A state condition already raised is not raised again; an occurrence inside the rule's cool-down is recorded but held for the digest; and the digest is one message listing what fired.</p>
<p dir="auto"><strong>Webhooks.</strong> A rule whose <code>actions</code> is 2 (webhook) or 3 (mail and webhook) POSTs one JSON object per event (<code>condition</code>, <code>state</code>, <code>severity</code>, <code>time</code>, <code>time_utc</code>, <code>summary</code>, <code>detail</code>, <code>server</code>) with three headers: <code>X-hMailServer-Timestamp</code>, <code>X-hMailServer-Signature: sha256=&lt;hex&gt;</code> and <code>X-hMailServer-Event</code>. It is signed under the rule's shared secret, as every webhook the server sends is; <a href="/topic/28266">the topic on integrating applications</a> shows how to verify it.</p>
<p dir="auto">A rule that calls a webhook is refused without an address and without a secret; <code>webhook_secret</code> is write-only and the listing says only <code>webhook_secret_set</code>. Only <code>https</code>, or plain <code>http</code> to a loopback address, is used. An attempt that does not get a 2xx is retried on the next pass, then after 1, 5 and 15 minutes, which is the default five attempts, and 60 minutes apart after that if the maximum is raised. After the last attempt the event is <strong>dead-lettered</strong>: kept, no longer retried, and reported once in the error log as <code>HM6543</code>.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Route</th>
<th>Does</th>
<th>Permission</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>GET /api/v1/alerts/rules</code></td>
<td>Every condition and its rule</td>
<td><code>view_configuration</code></td>
</tr>
<tr>
<td><code>PUT /api/v1/alerts/rules/{condition}</code></td>
<td>Change one, or create one for a condition nothing ships; a field left out keeps its value</td>
<td><code>manage_settings</code></td>
</tr>
<tr>
<td><code>GET /api/v1/alerts/events</code></td>
<td>What has fired, newest first, with the webhook's state</td>
<td><code>view_configuration</code></td>
</tr>
<tr>
<td><code>POST /api/v1/alerts/test</code></td>
<td>Raise a condition through the path a real one takes: <code>{"condition":"disk.low","summary":"...","occurrence":false}</code></td>
<td><code>manage_settings</code></td>
</tr>
<tr>
<td><code>POST /api/v1/alerts/run</code></td>
<td>Run one pass now</td>
<td><code>manage_server</code></td>
</tr>
</tbody>
</table>
<p dir="auto">All five are refused to every API key. The administrator password reaches them, and so does an account whose role holds the permission and reaches every domain. Neither the Control Panel nor the Deck has a page for the rules, and <code>hmctl</code> and the PowerShell module have no <code>alerts</code> or <code>audit</code> verbs; <code>hmctl api</code> reaches the routes.</p>
<h3><a class="anchor-offset" name="the-audit-trail"></a>The audit trail</h3>
<p dir="auto">One row per administrative change made over COM, REST or the Deck, in <code>hm_audit</code>: when (<code>audittime</code>, UTC); who (<code>auditactor</code>: <code>Administrator</code> over COM, <code>administrator</code> or <code>key:&lt;id&gt;</code> over REST, and an account signed in with its own password is its address over COM and <code>account:&lt;address&gt;</code> over REST and the Deck); the interface and, except over COM, the peer address; the object's type and name; the action (<code>created</code>, <code>updated</code> or <code>deleted</code>, also <code>unlocked</code>, <code>cleared</code>, <code>moved</code> and <code>move failed</code>, the last for a mailbox move that failed and could not be put back); the detail (the columns the change carried, or for a setting <code>Name: old -&gt; new</code>, ending <code>[role: &lt;name&gt;]</code> under a role); and the two hashes of the chain.</p>
<p dir="auto">Both kinds of setting are recorded: the <code>hm_settings</code> values and the <code>[Settings]</code> keys (in <code>hm_inisettings</code> since schema 6042), with the value they had. A key set for the first time reads <code>SmtpTarpitCount: (default) -&gt; 5</code>; returned to its default it reads <code>SmtpTarpitCount: 5 -&gt; (default)</code>, with the action <code>deleted</code>. A write of the value a setting already has records nothing.</p>
<p dir="auto"><strong>What is never recorded as a value.</strong> A password, key, token, secret, hash, salt or passphrase is recorded as <code>(changed)</code>, decided by the name of the column or setting, matched as a substring, so <code>MetricsServerAuthToken</code> and <code>PasswordPepper</code> are among them. Fifteen keys whose names only look like secrets, the seven <code>PasswordPolicy*</code> keys among them, are recorded with their values. The server's own writes (delivery, retention, greylisting, the index) are never recorded.</p>
<p dir="auto"><strong>Verifying the chain.</strong> Each row carries the SHA-256 of the row before it and of itself. <code>GET /api/v1/audit/verify</code> answers <code>{"intact","rows_checked","first_broken_id","reason"}</code>, and the reason tells a row that was <strong>edited</strong> from one that was <strong>removed</strong>. This makes tampering <strong>detectable, not impossible</strong>: whoever can write the table can recompute the whole chain. Rows hashed the older way, which only a build from before the 6.3.4 release can have written, did not cover a character above U+00FF; they still verify, with that weakness.</p>
<p dir="auto"><strong>Reading it.</strong> <code>GET /api/v1/audit?actor=&amp;object_type=&amp;action=&amp;since=&amp;until=&amp;limit=&amp;offset=</code> answers newest first; <code>actor</code> is a substring, so <code>key:</code> finds every change made with an API key, and <code>limit</code> is 1 to 1,000, default 100. It needs the administrator password, or an account whose role holds <code>view_audit</code> (the <code>auditor</code> role) and is not confined to named domains. Every API key is refused, with 401 rather than 403, so that it learns nothing from asking.</p>
<p dir="auto"><strong>Putting a change back.</strong> <code>POST /api/v1/audit/{id}/revert</code> writes a setting's old value back through the same setter, so the put-back is itself a row in the trail. It needs <code>manage_settings</code> and is refused with 409 for a row that is not a setting's change, a secret's row, a value the trail cut at 120 characters, and a setting this version no longer has.</p>
<p dir="auto"><strong>Where to see it.</strong> The Deck's <strong>Audit trail</strong> view has the filters, paging, <em>Verify the chain</em> and <em>Put back</em>. On Windows the Control Panel has the same page, over COM, at <strong>Monitoring &amp; troubleshooting → Audit trail</strong> (<strong>Compliance → Audit trail</strong> since 6.3.7; Ctrl+K takes the old route to it). Switching recording off is itself recorded. The trail, the rules and the events are not in the built-in backup.</p>
<p dir="auto"><strong>What it holds for compliance.</strong> A download of a discovery export is recorded on the trail alone, so with the trail off it is recorded nowhere. An erasure is recorded with the address it erased wherever it deletes from recorded tables (aliases, distribution-list recipients and, with the archive included, the archive index), and <code>audit_retention_days</code> is how those rows age out. <a href="/topic/28242">The compliance topic</a> covers eDiscovery and the erasure.</p>
<p dir="auto"><strong>What it does not record.</strong> Reads; what a restore replaces (the request is one row, <code>restore started</code>); creating or revoking a REST API key; releasing or deleting a quarantined message; creating, renaming or deleting a public folder; the <code>[Security]</code>, <code>[Directories]</code> and <code>[Database]</code> sections of <code>hMailServer.ini</code>; and a change nobody made through an interface. A change to the twelve syslog settings over COM, from the Control Panel's <strong>Logging</strong> page for one, is recorded in 6.3.4: the settings property setters carry an audit scope of their own. The wiki's syslog section, 16.2a, still describes the earlier state.</p>
<h3><a class="anchor-offset" name="syslog-and-the-journal-since-6.3.4"></a>Syslog and the journal (since 6.3.4)</h3>
<p dir="auto">Every entry the server logs can also be sent as RFC 5424 to a syslog collector over UDP, TCP or TLS. It is a <strong>copy</strong>: the files under <code>LogFolder</code> are written as before. On Windows the settings are the <em>syslog (RFC 5424)</em> card on the Control Panel's <strong>Logging</strong> page; on Linux they are keys of <code>PUT /api/v1/settings/logging</code> and the Control Deck, and <code>hmctl settings get logging</code> prints them. They take effect when the sink starts, at the next service start or <em>Reinitialize</em>, not when they are saved.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th><code>hm_settings</code> name</th>
<th>REST key</th>
<th>Default</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>SyslogEnabled</code></td>
<td><code>syslog_enabled</code></td>
<td>off</td>
<td>The whole feature</td>
</tr>
<tr>
<td><code>SyslogHost</code></td>
<td><code>syslog_host</code></td>
<td>empty</td>
<td><strong>Empty is not "off"</strong>: on Linux under systemd it selects the journal; on Windows nothing is sent, which the server says once in the application log</td>
</tr>
<tr>
<td><code>SyslogPort</code></td>
<td><code>syslog_port</code></td>
<td><code>514</code></td>
<td>514 for UDP and plain TCP; 6514 is the registered port for TLS</td>
</tr>
<tr>
<td><code>SyslogTransport</code></td>
<td><code>syslog_transport</code></td>
<td><code>0</code> (UDP)</td>
<td><code>0</code> UDP, <code>1</code> TCP, <code>2</code> TCP over TLS; the REST key takes <code>udp</code>, <code>tcp</code> or <code>tls</code></td>
</tr>
<tr>
<td><code>SyslogFacility</code></td>
<td><code>syslog_facility</code></td>
<td><code>2</code> (mail)</td>
<td>0 to 23; 16 to 23 are <code>local0</code> to <code>local7</code></td>
</tr>
<tr>
<td><code>SyslogMinimumSeverity</code></td>
<td><code>syslog_minimum_severity</code></td>
<td><code>6</code> (informational)</td>
<td>Entries less severe than this are not sent</td>
</tr>
<tr>
<td><code>SyslogLogTypes</code></td>
<td><code>syslog_log_smtp</code>, <code>syslog_log_pop3</code>, <code>syslog_log_imap</code>, <code>syslog_log_application</code>, <code>syslog_log_tcpip</code>, <code>syslog_log_debug</code></td>
<td><code>86</code></td>
<td>One bit mask: SMTP, POP3, application and IMAP on; TCP/IP and debug off</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>Errors are sent whatever the mask says.</strong> A message looks like this:</p>
<pre><code>&lt;22&gt;1 2026-09-15T14:21:09.284+01:00 mail.example.com hMailServer 4812 SMTPD [hmailserver@32473 thread="7412" session="41" client="203.0.113.9"] &lt;BOM&gt;RECEIVED: MAIL FROM:&lt;sender@example.org&gt;
</code></pre>
<p dir="auto">The message id is the log category (<code>SMTPD</code> and so on) or, on an error line carrying an hMailServer error number, that number, so <code>msgid == HM5165</code> is a usable filter at the collector. The structured data under <code>hmailserver@32473</code> carries <code>thread</code>, and <code>session</code> and <code>client</code> on a conversation line. <strong>UDP truncates each message to 1024 bytes</strong>, cutting the text and never the header; TCP and TLS frame each message with its length and truncate nothing below 65000 bytes. <strong>TLS verifies the collector's certificate</strong> against the machine's trust store and the configured host name, so set the host to the name in the certificate, not an IP address; no client certificate is offered.</p>
<p dir="auto"><strong>A collector that is down costs log lines, not mail.</strong> Entries go to a background thread over a queue of 4096 that drops the oldest when full; a stream that cannot connect backs off from one second to a minute; and the application log gets one line when an outage starts and one when it ends, with the number dropped. Nothing is retried from disk. Each step of a stream transport (the connection, the TLS handshake, one entry written) is given ten seconds, so a collector that accepts the connection and then goes quiet is a failure like a refused one, and a reinitialise or a service stop waits for that step at most.</p>
<p dir="auto">For rsyslog, in <code>/etc/rsyslog.d/30-hmailserver.conf</code> (UDP for the default transport, TCP for <code>SyslogTransport = 1</code>; the <code>stop</code> keeps the lines out of <code>/var/log/mail.log</code> too, so drop it if you want both):</p>
<pre><code class="language-rsyslog">module(load="imudp")
input(type="imudp" port="514")

module(load="imtcp")
input(type="imtcp" port="514")

if ($app-name == "hMailServer") then {
   action(type="omfile" file="/var/log/hmailserver.log"
          template="RSYSLOG_SyslogProtocol23Format")
   stop
}
</code></pre>
<p dir="auto">Without <code>RSYSLOG_SyslogProtocol23Format</code> rsyslog reformats to the older RFC 3164 shape and the structured data is lost. For TLS (<code>SyslogTransport = 2</code><img src="https://www.hmailserver.co.uk/assets/plugins/nodebb-plugin-emoji/emoji/android/1f61e.png?v=6eecd33477c" class="not-responsive emoji emoji-android emoji--disappointed" style="height:23px;width:auto;vertical-align:middle" title="):" alt="😞" /></p>
<pre><code class="language-rsyslog">module(load="imtcp"
       StreamDriver.Name="gtls"
       StreamDriver.Mode="1"
       StreamDriver.AuthMode="anon")
input(type="imtcp" port="6514")

global(DefaultNetstreamDriverCAFile="/etc/ssl/certs/ca.pem"
       DefaultNetstreamDriverCertFile="/etc/rsyslog.d/collector-cert.pem"
       DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/collector-key.pem")
</code></pre>
<p dir="auto">A self-signed collector certificate has to be installed as trusted on the hMailServer machine, or the handshake is refused and nothing is sent.</p>
<p dir="auto"><strong>The journal, on Linux only</strong>, needs no collector. Where the server runs as the packaged <code>hmailserver.service</code>, switch the sink on and leave the collector host empty:</p>
<pre><code class="language-console">$ hmctl settings set logging --set syslog_enabled=true
$ sudo systemctl restart hmailserver
$ journalctl -u hmailserver -f
</code></pre>
<p dir="auto">Beside the standard fields the journal gets <code>HMAILSERVER_CATEGORY</code>, <code>HMAILSERVER_MSGID</code>, <code>HMAILSERVER_THREAD</code>, <code>HMAILSERVER_SESSION</code> and <code>HMAILSERVER_CLIENT</code>:</p>
<pre><code class="language-console">$ journalctl -u hmailserver HMAILSERVER_SESSION=41
$ journalctl -u hmailserver HMAILSERVER_MSGID=HM5165
</code></pre>
<p dir="auto">If a collector host is configured the journal is not used. The start of the sink is itself logged, as <code>Syslog: sending RFC 5424 log entries to &lt;host&gt;:&lt;port&gt; over UDP, facility 2.</code> or <code>Syslog: writing log entries to the systemd journal.</code>; a server that logs neither has the feature off. <strong>Not sent</strong>: the AWStats log, the backup log and the event-script log.</p>
<h3><a class="anchor-offset" name="per-domain-reports-since-6.3.4"></a>Per-domain reports (since 6.3.4)</h3>
<p dir="auto"><code>GET /api/v1/reports</code> is an index of the sections, the state of their three sources and what this server cannot answer. A report drawn while its source was off is empty, which is not the same statement as "nothing happened"; each section's <code>note</code> says which it is. <code>GET /api/v1/reports/{section}</code> answers one section, the Deck's <strong>Reports</strong> view draws the summary, and <code>hmctl report</code> prints a section or saves it as CSV. There is no Control Panel page.</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Section</th>
<th>Counted from</th>
<th>Says</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>traffic</code></td>
<td>the message trace</td>
<td>Per day and per local domain: <code>incoming</code>, <code>outgoing</code>, <code>failed_incoming</code>, <code>failed_outgoing</code></td>
</tr>
<tr>
<td><code>failures</code></td>
<td>the message trace</td>
<td>Per local domain and SMTP status code</td>
</tr>
<tr>
<td><code>senders</code>, <code>recipients</code></td>
<td>the message trace</td>
<td>The local addresses that sent or received the most, with their failures</td>
</tr>
<tr>
<td><code>mailboxes</code></td>
<td><code>hm_messages</code></td>
<td>The largest mailboxes as they are now: a size, not a history</td>
</tr>
<tr>
<td><code>volume</code></td>
<td>the metric history, and the daily per-domain sample</td>
<td>Processed, delivered, deferred, bounced, spam and viruses per day, with <code>by_domain</code> rows of spam and viruses</td>
</tr>
<tr>
<td><code>storage</code></td>
<td>the same</td>
<td>The store's size per day and <code>growth_bytes</code>, with <code>by_domain</code> rows of each domain's size</td>
</tr>
<tr>
<td><code>summary</code></td>
<td>all three sources</td>
<td>Every section the credential may see, with an <code>omitted</code> list and the reason</td>
</tr>
<tr>
<td><code>quota</code></td>
<td>the store</td>
<td>Every mailbox with a limit and at least one message, nearest its limit first, as a share of the limit: a share now, not a history</td>
</tr>
<tr>
<td><code>countries</code></td>
<td>the metric history and the country counters</td>
<td>What a country policy refused, per day; the split by country is since the server last started, not per day</td>
</tr>
</tbody>
</table>
<p dir="auto">The last two are described in <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/QuotaPolicy.md" rel="nofollow ugc">QuotaPolicy.md</a> and <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/CountryBlocking.md" rel="nofollow ugc">CountryBlocking.md</a>, not in <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Reports.md" rel="nofollow ugc">Reports.md</a>.</p>
<p dir="auto"><strong>Parameters.</strong> <code>from</code> and <code>to</code> as <code>YYYY-MM-DD</code>, both inclusive, defaulting to the last 30 days and never more than 366; <code>domain</code>, one hosted domain (a domain not hosted here is a 404); <code>top</code>, 1 to 200, default 10; <code>format=csv</code>, refused for <code>summary</code>. In CSV a cell starting with <code>=</code>, <code>+</code>, <code>-</code> or <code>@</code> is prefixed with an apostrophe.</p>
<p dir="auto"><strong>Three things decide whether a report means anything.</strong> The message trace is off by default (<code>MessageTraceEnabled=0</code>), and while it is off the four sections counted from it are empty. Processed, delivered, deferred and bounced cannot be given per domain, because those counters carry no domain; spam, viruses and storage can, since schema 6062 added the daily sample in <code>hm_domainsamples</code>, which starts the day it was first taken. And only hosted domains are counted.</p>
<p dir="auto"><strong>Authorisation.</strong> The administrator password reads everything; every other credential needs both <code>view_configuration</code> and <code>view_message_trace</code>. <code>domainadmin</code> and <code>auditor</code> hold both; <code>helpdesk</code> is refused. A key restricted to named domains sees only those and is refused 403 for another. <strong>On <code>volume</code> and <code>storage</code> <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Reports.md" rel="nofollow ugc">Reports.md</a> contradicts itself</strong>: its <em>Authorisation</em> section refuses them to such a key outright, while its section <em>What cannot be answered, and what it would take</em> (and, for <code>volume</code>, its table of sections under <em>The route</em>) gives a credential restricted to domains the per-domain rows, as the wiki's section 16.6a does. Test both with your own restricted key before a script relies on either.</p>
<p dir="auto"><strong>The cost.</strong> One report makes at most three grouped queries; the trace read is capped at 100 000 grouped rows and the answer says <code>truncated</code> when it reaches the cap.</p>
<pre><code>hmctl report sections
hmctl report traffic --from 2026-09-01 --to 2026-09-15 --domain example.com
</code></pre>
<h3><a class="anchor-offset" name="following-one-connection-live"></a>Following one connection live</h3>
<p dir="auto">Since 6.3.4 the Deck's <strong>Logs</strong> page lists the sessions open now and those recently ended, and <em>Follow</em> shows one session's lines as they are written, from an in-memory ring of the last 4,096 log entries that no restart keeps; it needs <code>view_logs</code>. <a href="/topic/28220">Reading the logs</a> covers following a connection in full, and the log files themselves.</p>
<h3><a class="anchor-offset" name="where-to-read-more"></a>Where to read more</h3>
<ul>
<li>Documents at v6.3.4: <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/AlertsAndAuditTrail.md" rel="nofollow ugc">AlertsAndAuditTrail.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Syslog.md" rel="nofollow ugc">Syslog.md</a>, <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Reports.md" rel="nofollow ugc">Reports.md</a> and <a href="https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/FollowConnection.md" rel="nofollow ugc">FollowConnection.md</a></li>
<li>Wiki: <a href="https://gitlab.com/hmailserver/hmailserver/-/wikis/Monitoring-and-Health" rel="nofollow ugc">Monitoring and Health</a>, sections 16.2a, 16.6a, 16.7a and 16.7b</li>
<li>The public documentation: <a href="https://www.progressiverobot.com/hmailserver-documentation/#162-logs-on-disk" rel="nofollow ugc">16.2 Logs on disk</a></li>
<li>On this forum: <a href="/topic/28272">Monitoring and health</a> for the metrics, the probes, the dashboard and the SNMP agent; <a href="/topic/28237">Administrator roles</a> for the permissions named here. See also <a href="/topic/28192">The Control Deck</a> and <a href="/topic/28189">hMailServer on Linux: what you get and what you do not</a></li>
</ul>
]]></description><link>https://www.hmailserver.co.uk/topic/28273/alerts-the-audit-trail-syslog-and-the-journal-and-per-domain-reports</link><generator>RSS for Node</generator><lastBuildDate>Fri, 06 Nov 2026 08:51:50 GMT</lastBuildDate><atom:link href="https://www.hmailserver.co.uk/topic/28273.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 27 Sep 2026 19:55:13 GMT</pubDate><ttl>60</ttl></channel></rss>