-
Notifications
You must be signed in to change notification settings - Fork 3
The COM API and Scripting
This page began as a chapter of the 6.2.10 manual and has been corrected for 6.2.28. The Control Panel's pages are grouped differently now, so the paths below use today's groups; the TLS ports 465, 993 and 995 exist only after you create them on the TCP/IP ports page (a fresh install seeds 25, 587, 110 and 143); and everything added since 6.2.10 is in Changes-Since-6210. Where a value here disagrees with the Settings Reference, which is generated from the code, the reference is right.
hMailServer exposes a full COM API. Anything the Control Panel can do, a script can do - it is the same interface. The Control Panel is a COM client and nothing more.
There are two quite different things on this page and it is worth keeping them apart:
| The COM API | Event scripts | |
|---|---|---|
| Who runs it | You, from PowerShell, VBScript, C#, anything that speaks COM | The server, in-process, while mail is moving |
| When | Whenever you like | At fifteen defined points in the mail flow |
| Runs as | You | The service account, usually LocalSystem |
| Failure costs | Your script | Delivery for every message behind it |
| Turned on by | Nothing; it is always there | Settings.Scripting.Enabled |
Everything up to section 23.5 is the API. Section 23.6 onwards is event scripts.
For the full object-by-object reference - all 94 coclasses, every route of the
REST API, and what each Settings sub-object holds - see APIs Reference.
- One type library,
hMailServer, with 94 coclasses. The root isApplication(ProgIDhMailServer.Application). - Every interface is a dual
IDispatchinterface, so late binding works without registering the type library.CreateObject,New-Object -ComObjectand C#dynamicall work on a machine where only the server is installed. - Early binding - a C# interop assembly, a
Dim x As hMailServer.Account- depends on vtable order. New members are therefore always appended, never inserted, so an interop assembly built against an older release keeps working. - The installer's admintools component exists only to register the type library, so that scripts on another machine can administer this one. If you do not script remotely, you do not need it.
# Local
$app = New-Object -ComObject 'hMailServer.Application'
# Remote, over DCOM, against a machine where admintools is registered
$app = [Activator]::CreateInstance([Type]::GetTypeFromProgID('hMailServer.Application', 'mail01'))The Control Panel connects to a remote host exactly that way, which is why it needs no agent on the far end.
$app = New-Object -ComObject 'hMailServer.Application'
$account = $app.Authenticate('Administrator', 'your-admin-password')
if (-not $account) { throw 'Authentication failed.' }Authenticate returns an Account object, or $null on failure. Three
credentials work:
| Sign in as | Gets |
|---|---|
Administrator with [Security] AdministratorPassword from hMailServer.INI
|
Server administrator |
A mailbox address whose AdminLevel is 2 |
Server administrator |
A mailbox address whose AdminLevel is 1 |
Domain administrator: their own domain only |
Two things about this that are not obvious:
If the administrator password is empty, and no administrator TOTP secret is
enrolled, every COM session starts already authenticated as a server
administrator - COMAuthentication::AttempAnonymousAuthentication creates a
dummy Administrator account. This is the historical behaviour and it is why
setting an administrator password is the first line of Security Hardening.
A second factor on the administrator credential changes the call you must
make. With Settings.EnrolAdministratorTOTP() used (6.2.27), Authenticate
refuses the administrator outright - a stolen password is not a credential on its
own - and you must call:
if ($app.AdministratorTOTPEnabled) { # readable BEFORE authenticating
$app.AuthenticateWithCode('Administrator', $password, $code) | Out-Null
} else {
$app.Authenticate('Administrator', $password) | Out-Null
}AuthenticateWithCode is the only path that can satisfy a second factor -
a mail client has nowhere to type one, which is exactly why an account with a
factor enrolled uses an app password for IMAP, POP3 and SMTP instead.
Each interface object loads its state through a private LoadSettings() that
first asks GetIsServerAdmin(). If you are not entitled to the object, that load
does nothing, the interface's pointers stay null, and every member then returns
an error HRESULT:
You do not have access to this property / method. Ensure that hMailServer.Application.Authenticate() is called with proper login credentials.
In PowerShell that surfaces as a terminating exception; in VBScript as a
trappable error; in C# as a COMException. In 6.2.10 this was a real defect
worth remembering: fifteen methods returned false from a function whose return
type is HRESULT, and false is 0, which is S_OK - so an unauthorized
caller got "success", and five of them had not written their out-parameter, so
"success" came with uninitialized memory. If you script against the COM API,
be on 6.2.10 or later and check return values.
flowchart TD
App["Application<br/>hMailServer.Application"]
App --> Auth["Authenticate<br/>AuthenticateWithCode<br/>AdministratorTOTPEnabled"]
App --> Dom["Domains"]
App --> Set["Settings"]
App --> Rul["Rules - global"]
App --> Sta["Status"]
App --> Uti["Utilities"]
App --> Dbs["Database"]
App --> Bak["BackupManager"]
App --> Glo["GlobalObjects"]
App --> Lnk["Links"]
App --> Dia["Diagnostics"]
Dom --> D1["Domain: Name, Active, MaxSize,<br/>DKIM, relay, retention"]
D1 --> Acc["Accounts"]
D1 --> Ali["Aliases"]
D1 --> Dls["DistributionLists"]
D1 --> Dal["DomainAliases"]
Acc --> A1["Account: Address, Password, Active,<br/>MaxSize, Size, AdminLevel"]
A1 --> Msg["Messages"]
A1 --> Fol["IMAPFolders"]
A1 --> Arl["Rules - this account"]
A1 --> Fet["FetchAccounts"]
A1 --> Apw["AppPasswords"]
A1 --> Sie["SieveScript, TOTPEnabled,<br/>vacation, forwarding, signature"]
Set --> S1["AntiSpam - owns Quarantine"]
Set --> S2["AntiVirus"]
Set --> S3["Backup"]
Set --> S4["Directories"]
Set --> S5["Logging"]
Set --> S6["Routes"]
Set --> S7["Scripting"]
Set --> S8["SecurityRanges"]
Set --> S9["SSLCertificates"]
Set --> S10["TCPIPPorts"]
Set --> S11["ServerMessages, Groups,<br/>IncomingRelays, PublicFolders,<br/>MessageIndexing, Cache"]
Glo --> G1["DeliveryQueue"]
Glo --> G2["MessageTrace"]
Glo --> G3["Languages"]
Every collection - Domains, Accounts, Rules, Criterias, Actions, all of
them - offers the same shape: Count, Item(index), ItemByDBID(id), Add(),
Refresh(), Delete(index) and DeleteByDBID(id), with ItemByName or
ItemByAddress where a name exists. Items have Save() and Delete().
Add()does not persist. It returns a new, unsaved object. Set the properties, then callSave(). A script that forgetsSave()looks as though it worked and changes nothing.
$app = New-Object -ComObject 'hMailServer.Application'
$app.Authenticate('Administrator', 'your-admin-password') | Out-Null
# Add a domain
$domain = $app.Domains.Add()
$domain.Name = 'example.com'
$domain.Active = $true
$domain.Save()
# Add an account
$account = $domain.Accounts.Add()
$account.Address = 'alice@example.com'
$account.Password = 'a-strong-password'
$account.Active = $true
$account.MaxSize = 1000 # MB, 0 = unlimited
$account.Save()
# Report on every mailbox
foreach ($d in $app.Domains) {
foreach ($a in $d.Accounts) {
'{0,-40} {1,8} MB used' -f $a.Address, [math]::Round($a.Size, 1) # Size is already in MB
}
}Output shape:
alice@example.com 12.4 MB used
bob@example.com 301.9 MB used
postmaster@example.com 0.0 MB used
Account.Sizeis megabytes (bytes / 1048576, to three decimals). Dividing it by1MBagain - which older examples do - prints0for every mailbox.Message.Size, by contrast, is kilobytes, and theMessage sizerule criterion is bytes. Three units, three objects; check which one you have.
Find one account without walking every domain:
$domain = $app.Domains.ItemByName('example.com')
$account = $domain.Accounts.ItemByAddress('alice@example.com')Send a message from a script, without an SMTP client. Message is a creatable
coclass in its own right, and Save() on a new one queues it for delivery:
$m = New-Object -ComObject 'hMailServer.Message'
$m.FromAddress = 'postmaster@example.com'
$m.From = 'Postmaster <postmaster@example.com>'
$m.AddRecipient('Alice', 'alice@example.com')
$m.Subject = 'Scheduled maintenance tonight'
$m.Body = 'The server will restart at 22:00.'
$m.Save()(Application.SubmitEMail() is a different thing despite the name: it is a
method with no arguments that pushes messages already sitting in the database
into delivery, for the case where a row was inserted by hand.)
Look at the delivery queue and make it try again now:
$app.Status.UndeliveredMessages # tab-separated text, one row per message
$app.GlobalObjects.DeliveryQueue.ResetDeliveryTime()
$app.GlobalObjects.DeliveryQueue.StartDelivery()Check a Sieve script before you store it, and set one:
$err = $app.Utilities.CheckSieveSyntax($script) # empty string = valid
if ($err) { throw $err }
$account.SieveScript = $script # writes the file; no Save() neededProve what a rule criterion really does, with no message involved:
$app.Utilities.CriteriaMatch('*invoice*', 8, 'Your Invoice 42') # 8 = eMTWildcardRun a backup:
$b = $app.Settings.Backup
$b.BackupDomains = $true; $b.BackupSettings = $true; $b.BackupMessages = $true
$b.Destination = 'D:\backups'
$app.BackupManager.StartBackup()Shipped examples live in hmailserver/Addons/Utilities: StartBackup.vbs,
MakeServiceDependent.vbs, EncryptAllPasswords.vbs, LoadAllMessages.vbs,
RemoveUnusedAccounts.vbs, DecryptBlowfish.vbs.
Not everything is a first-class property. The keys that live in
hMailServer.INI are reachable generically:
$app.Settings.IniSettingNames # every key the server knows
$app.Settings.GetIniSetting('ManageSieveServerPort')
$app.Settings.SetIniSetting('ManageSieveServerPort', '4190')
$app.Settings.DeleteIniSetting('HttpProxy')Most INI settings are read at service start, so a change through this route usually needs a restart before it does anything. The Settings Reference marks which are which.
Two Control Panel pages, both under Maintenance: Advanced, whose Scripting tab turns the engine on and chooses the language, and Event scripts, which edits the file.

| Setting | Where | Default | Notes |
|---|---|---|---|
Settings.Scripting.Enabled |
Maintenance → Advanced → Scripting | off | Nothing fires while this is off |
Settings.Scripting.Language |
Maintenance → Advanced → Scripting | VBScript |
Or JScript. An unrecognised value gives an extension that names no file, so the script is empty and nothing fires |
Settings.Scripting.Directory |
[Directories] EventFolder in the INI |
<install>\Events |
|
Settings.Scripting.CurrentScriptFile |
derived |
<EventFolder>\EventHandlers.vbs or .js
|
One file. There is no include mechanism |
ScriptTimeout |
INI [Settings]
|
60 seconds | 0 disables the watchdog |
ScriptAllowedObjects |
INI [Settings]; editor on Maintenance → Advanced → Scripting |
* |
Section 23.9 |
Settings.Scripting.Reload() re-reads the file, CheckSyntax() compiles it and
returns the error text (empty means clean). The Control Panel's Save & reload
button writes a .bak first, then does both.
sequenceDiagram
participant Srv as Server thread
participant SS as ScriptServer
participant Eng as Script engine
participant Fn as Your handler
Srv->>SS: FireEvent OnAcceptMessage, with the caller line and the objects
SS->>SS: Is scripting enabled - if not, return
SS->>SS: Is OnAcceptMessage declared in the loaded script - if not, return
SS->>SS: Take the script text and the language together, under one lock
SS->>Eng: New engine, then publish HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE and Result
SS->>Eng: Add the WHOLE script file, then one more line calling the handler
Note over SS,Eng: Watchdog armed for ScriptTimeout seconds
Eng->>Eng: Run every top-level statement in the file
Eng->>Fn: Then call your handler
Fn-->>Eng: Sets Result.Value and Result.Message
Eng-->>SS: Returns
SS->>SS: Disarm the watchdog and terminate the engine
SS-->>Srv: The server reads Result and acts
Two consequences of that picture, both of which surprise people:
- The whole file is re-parsed and re-executed for every single event. Code outside a function runs on every message, every connection, every error. Put nothing at the top level except constants and function declarations - no database connections, no file opens, no loops.
- Nothing is shared between events. A fresh engine is created and terminated each time, so there are no globals that survive, and no state you can accumulate in memory. Use a file, or the database, or a header on the message.
Every handler is optional. The server checks, when the script is loaded, which of these names the file declares, and fires only those - so an absent handler costs nothing at all.
| Handler | Called as | Fires when |
Result is read? |
|---|---|---|---|
OnClientConnect |
(HMAILSERVER_CLIENT) |
Any TCP connection is accepted, before a greeting | Yes |
OnHELO |
(HMAILSERVER_CLIENT) |
The SMTP client sent HELO or EHLO | Yes |
OnClientLogon |
(HMAILSERVER_CLIENT) |
An SMTP, POP3 or IMAP client finished a logon attempt - successful or not. Client.Authenticated says which, and Client.Username names who was tried. This is the hook to build auditing or a script-side lockout on |
no |
OnClientValidatePassword |
(HMAILSERVER_ACCOUNT, "password") |
A password is being checked, before the built-in check | Yes |
OnSMTPData |
(HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE) |
The DATA command arrived, before the body | Yes |
OnAcceptMessage |
(HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE) |
The body has been received and is about to be queued | Yes |
OnRecipientUnknown |
(HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE) |
A RCPT TO named an address this server does not host | no |
OnTooManyInvalidCommands |
(HMAILSERVER_CLIENT, HMAILSERVER_MESSAGE) |
An SMTP client sent too many invalid commands | no |
OnDeliveryStart |
(HMAILSERVER_MESSAGE) |
First step of a delivery attempt, before virus scanning | Yes |
OnDeliverMessage |
(HMAILSERVER_MESSAGE) |
After virus scanning and global rules, before the recipient split | Yes |
OnDeliveryFailed |
(HMAILSERVER_MESSAGE, "recipient", "error") |
Once per failed recipient; may fire several times per message | no |
OnExternalAccountDownload |
(HMAILSERVER_FETCHACCOUNT, HMAILSERVER_MESSAGE, "uid") |
A message was fetched from an external POP3/IMAP account. The message argument is Nothing/null when there is no message |
Yes |
OnError |
(severity, id, "source", "description") |
Anything is written to the ERROR log | no |
OnBackupCompleted |
() |
A backup finished | no |
OnBackupFailed |
("reason") |
A backup failed | no |
OnError's severity is 1 Critical, 2 High, 3 Medium, 4 Low, and its id
is the HM<nnnn> number without the prefix. Reporting an error from inside
OnError would fire it again, so the server sets a per-thread guard for the
duration of the dispatch - but a handler that raises a script error inside
OnError is still the one place a runaway is easy to write.
Result is published into the script for the events marked above. Set
Result.Value, and for the refusal cases Result.Message.
| Event | Result.Value |
Effect |
|---|---|---|
OnClientConnect |
1 |
Disconnect immediately, before the greeting |
OnHELO |
1 |
554 5.7.1 Rejected |
2 |
554 5.7.1 <Result.Message> |
|
3 |
453 4.7.0 <Result.Message> - a temporary refusal |
|
OnSMTPData |
1 / 2 / 3
|
Exactly as OnHELO
|
OnAcceptMessage |
1 / 2 / 3
|
Exactly as OnHELO. This is the usual place to reject a message |
OnClientValidatePassword |
0 |
Let the user in without checking the password |
1 |
Refuse the logon | |
anything else (default 2) |
Fall through to the normal check | |
OnDeliveryStart |
1 |
Delete the message; logged as "Action triggered by script subscribing to OnDeliveryStart" |
OnDeliverMessage |
1 |
Delete the message; the same log line, naming OnDeliverMessage
|
OnExternalAccountDownload |
1 |
Delete from the remote server immediately |
2 |
Delete after Result.Parameter days |
|
3 |
Never delete from the remote server |
Everything else - OnClientLogon, OnRecipientUnknown,
OnTooManyInvalidCommands, OnDeliveryFailed, OnError, OnBackupCompleted,
OnBackupFailed - is notification only. Setting Result there does nothing.
OnClientValidatePasswordreturning0is a full authentication bypass for that account, on every protocol. It is the single most dangerous line you can write in an event script. If you use it to bridge to another directory, fail closed: return1when your lookup errors, not0.
HMAILSERVER_CLIENT - Port, IPAddress, Username, HELO,
Authenticated, EncryptedConnection, CipherVersion, CipherName,
CipherBits, SessionID. All read-only. The cipher properties are populated
only on a TLS connection.
HMAILSERVER_MESSAGE - the full Message interface: Subject, From,
FromAddress, To, CC, Date, Body, HTMLBody, Charset, Attachments,
Headers, HeaderValue(name) (read and write), Recipients,
AddRecipient, ClearRecipients, HasBodyType, Flag(eMessageFlag), Size
(KB), State, DeliveryAttempt, Filename, UID, InternalDate, Copy,
RefreshContent, Save.
HMAILSERVER_ACCOUNT (OnClientValidatePassword only) - a freshly loaded
Account, deliberately not the cached one.
HMAILSERVER_FETCHACCOUNT (OnExternalAccountDownload only) - the external
account the message came from.
Result - Value (long), Parameter (int), Message (string).
EventLog - published into every event, whether or not the event has a
Result. EventLog.Write("text") appends a line to
<log directory>\hmailserver_events.log. This is the debugger for event scripts:
there is no console, no breakpoint and no state that survives the call, so a
Write at the top of a handler is how you find out whether it ran at all.
Sub OnClientLogon(oClient)
Call EventLog.Write("logon " & oClient.Username & " from " & oClient.IPAddress & _
" ok=" & CStr(oClient.Authenticated) & _
" tls=" & CStr(oClient.EncryptedConnection))
End Subproduces, one tab-separated line per call:
4812 "2026-09-08 11:04:22.117" "logon alice@example.com from 203.0.113.9 ok=True tls=True"
Sub OnAcceptMessage(oClient, oMessage)
' Tag likely invoice fraud, but do not refuse it - a false positive here
' would lose real mail, and the tag lets a rule or a Sieve script file it.
If InStr(LCase(oMessage.Subject), "urgent invoice") > 0 Then
oMessage.HeaderValue("X-Suspicious") = "possible-invoice-fraud"
oMessage.Save
End If
' Refuse anything from one sender, with a reason the sender can read.
If LCase(oMessage.FromAddress) = "spammer@example.org" Then
Result.Value = 2
Result.Message = "This server does not accept mail from that address."
End If
End SuboMessage.Save is what writes the header back to the file on disk. Without it,
the change is lost when the engine is torn down.
The Control Panel's Insert template... button on the Event scripts page
supplies three ready-made OnAcceptMessage starters: an external antivirus or
DLP call, a webhook, and an HTTP API verdict.
A rule's Run script function action calls any function in the same file:
Function StampReceivedDate(oMessage)
oMessage.HeaderValue("X-Received-Date") = Now()
oMessage.Save
End FunctionIt is invoked as StampReceivedDate(HMAILSERVER_MESSAGE), with Result
published but ignored, and the message is reloaded from disk afterwards, so
anything you save is visible to the rest of the rule set. See
Rules and Sieve.
Event scripts run inside the mail flow, on the thread that is doing the work.
| Situation | What happens |
|---|---|
| The script takes a long time | Everything behind it waits. An OnAcceptMessage that takes two seconds caps this server at one message every two seconds on that connection |
The script exceeds ScriptTimeout (default 60 s) |
A watchdog interrupts the engine. HM5019 at High severity: "The script <event> did not complete within N seconds and was interrupted. An interrupt aborts script execution, but cannot release a handler which is blocked inside a COM call." When it is OnError itself that was killed, the message goes to the log without firing OnError again |
| The script raises an error | The engine reports it; the event's Result keeps whatever it had, which for most events means "carry on" |
| The script file does not compile on reload | HM5710: the previous script stays in force, whole - contents, language and handler flags together. On a cold start it is HM5016 instead: nothing is registered until it is fixed |
| Top-level code in the file hangs | HM5021, and the load is abandoned: "Code outside a function runs when the file is loaded, so it must return promptly. The script has not been loaded." Handler discovery would otherwise run the file another fifteen times |
| An exception escapes the load | HM5017; whatever was loaded before is untouched |
A load is deliberately all or nothing. The handler flags gate
security-relevant events - OnClientLogon and OnClientValidatePassword among
them - so the server must never advertise a handler it cannot run. Keeping the
last known-good script is the conservative choice: a typo in a hot reload must
not silently switch off an anti-spam or a logon hook on a running server.
The advice is old and it is still the advice, for a reason this page can now name: an event script is code running as LocalSystem on the thread that delivers your mail, re-executed from the top for every event, with the power to accept a logon and to delete a message. Try it somewhere else first.
Until this setting existed, CreateObject (VBScript) and new ActiveXObject
(JScript) could instantiate any COM class on the machine:
WScript.Shell runs programs, Scripting.FileSystemObject reads and writes the
disk, ADODB.Connection opens databases. A writable script file was therefore
the same thing as a shell as LocalSystem.
The script engines ask their host before creating an object - the
IInternetHostSecurityManager mechanism Internet Explorer used to sandbox pages -
and ScriptAllowedObjects is the answer the host gives.
[Settings]
; Any class at all - the behaviour before the setting existed, and still the default
ScriptAllowedObjects=*
; Nothing beyond hMailServer's own objects
ScriptAllowedObjects=
; Exactly these, by ProgID or by CLSID in braces
ScriptAllowedObjects=WScript.Shell,MSXML2.ServerXMLHTTP,{0D43FE01-F093-11CF-8940-00A0C9054228}| Value | Meaning |
|---|---|
| absent from the file | Treated as *. A setting introduced by an upgrade must not break the scripts an installation already runs |
* |
Every class |
| empty | No class. The objects the server hands the script - HMAILSERVER_MESSAGE and the rest - are unaffected; those are published, not created |
| a comma-separated list | Only those, matched on the registered ProgID (case-insensitively) or on the CLSID |
Matching is on the ProgID the class registers, so listing the version-independent name also covers the versioned one - both register the same class.
What a refusal looks like. The class fails inside the script with the engine's own can't create object error, 429, which the script can trap like any other failure, and one application-log line names the class and the setting. It is not a crash and not a silent no-op.
The editor is on the Scripting tab of Maintenance → Advanced, pre-filled
with * so that saving the page cannot turn "any object, as shipped" into "none"
behind a running script's back. It applies after a service restart.
The three templates the Control Panel inserts use
WScript.ShellandMSXML2.ServerXMLHTTP. If you tighten this setting, those two are the names to start your list with.
| Symptom | Cause | Fix |
|---|---|---|
| Every property raises "You do not have access to this property / method" | Not authenticated, or authenticated as a domain administrator reaching outside the domain | Check Authenticate returned an object, not $null
|
Authenticate returns $null for the administrator and the password is right |
A second factor is enrolled | Read AdministratorTOTPEnabled, then AuthenticateWithCode
|
| A script that "worked" changes nothing |
Add() without Save(), or a property set on an object that was released before Save()
|
Add Save(). In PowerShell, keep the object in a variable rather than chaining |
| Early-bound C# breaks after an upgrade | The interop assembly is stale | Regenerate it. Members are appended, never reordered, so a regenerate is all that is needed |
| No event ever fires |
Settings.Scripting.Enabled is off; or the language does not match the file extension; or the file declares no handler by an exact name |
Check Settings.Scripting.CurrentScriptFile names the file you are editing, then Check syntax
|
| One event fires and another does not | Handler names are matched exactly. OnErrorLog is not a handler; the name is OnError
|
|
| Events stopped firing after an edit | The reload failed and the previous script is still in force - HM5710 | Read the error log; it quotes the compile error |
| Mail is slow, and the slowness scales with volume | Top-level code in the script file, executed once per event | Move it inside a function |
| HM5019 in the log | A handler hit ScriptTimeout
|
Make the handler faster, or raise ScriptTimeout. An interrupt cannot release a handler blocked inside a COM call |
CreateObject fails with 429 for a class that exists |
ScriptAllowedObjects does not list it |
Add its ProgID, or set *, then restart the service |
| Subject | File |
|---|---|
| Interfaces, coclasses, enumerations, help strings | hmailserver/source/Server/hMailServer/hMailServer.idl |
| Authentication, anonymous administrator, the refusal text |
Server/COM/COMAuthentication.cpp, COMAuthenticator.h
|
The LoadSettings / GetAccessDenied pattern |
any Server/COM/Interface*.cpp
|
| Event dispatch, the per-event re-execution, the watchdog, the all-or-nothing load |
Server/Common/Scripting/ScriptServer.cpp and .h
|
Which events exist and what Result means |
Server/Common/Scripting/Events.cpp, Server/SMTP/SMTPConnection.cpp, Server/Common/TCPIP/TCPServer.cpp, Server/Common/Util/PasswordValidator.cpp, Server/ExternalFetcher/ExternalFetchClientBase.cpp, Server/Common/Application/ErrorManager.cpp, BackupManager.cpp
|
| The object-creation policy and how a refusal is produced |
Server/Common/Scripting/ScriptObjectPolicy.cpp, ScriptSite.h
|
ScriptTimeout, ScriptAllowedObjects, EventFolder
|
Server/Common/Application/IniFileSettings.cpp |
| Shipped example scripts | hmailserver/Addons/Utilities |
hMailServer 6.3.3 · AGPL-3.0-or-later · Repository · Report a documentation error
Hmail Server — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- The Control Panel
- Your First Domain and Mailbox
- Connecting a Mail Client
- DNS for Your Domain
2. Secure it
3. Operate it
- Monitoring and Health
- Backup and Restore
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Routes and Relays
- The COM API and Scripting
- The REST API
- Command Line
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey