Skip to content

The COM API and Scripting

chrisholloway5 edited this page Sep 8, 2026 · 3 revisions

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.


23.1 What you are connecting to

  • One type library, hMailServer, with 94 coclasses. The root is Application (ProgID hMailServer.Application).
  • Every interface is a dual IDispatch interface, so late binding works without registering the type library. CreateObject, New-Object -ComObject and C# dynamic all 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.


23.2 Authenticating, and what happens if you do not

$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.

Authorization: how a refusal reaches you

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.


23.3 The object model at a glance

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"]
Loading

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 call Save(). A script that forgets Save() looks as though it worked and changes nothing.


23.4 From PowerShell

$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.Size is megabytes (bytes / 1048576, to three decimals). Dividing it by 1MB again - which older examples do - prints 0 for every mailbox. Message.Size, by contrast, is kilobytes, and the Message size rule criterion is bytes. Three units, three objects; check which one you have.

More things worth having

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() needed

Prove what a rule criterion really does, with no message involved:

$app.Utilities.CriteriaMatch('*invoice*', 8, 'Your Invoice 42')   # 8 = eMTWildcard

Run 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.


23.5 Reading an INI setting from a script

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.


23.6 Event scripts

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.

The Event scripts page, with Save and reload, Check syntax, and the template inserter

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.

How an event actually reaches your function

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
Loading

Two consequences of that picture, both of which surprise people:

  1. 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.
  2. 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.

The fifteen events

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.

What Result does, event by event

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.

OnClientValidatePassword returning 0 is 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: return 1 when your lookup errors, not 0.

The objects you are handed

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 Sub

produces, 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"

A worked handler

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 Sub

oMessage.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.

Calling your own function from a rule

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 Function

It 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.


23.7 What a slow or broken script costs

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.


23.8 Test on a server that is not carrying your mail

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.


23.9 ScriptAllowedObjects: what a script may create

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.Shell and MSXML2.ServerXMLHTTP. If you tighten this setting, those two are the names to start your list with.


23.10 When something does not work

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

Where these facts come from

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

Clone this wiki locally