Skip to content
  • Categories
  • Recent
  • Popular
  • Tags
  • Users
  • Groups
  • Documentation
  • Downloads
  • Report a bug
  • GitHub mirror
  • Paid support
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
hMailServer Community Forum
hMailServer 6.3.8 is the current release, signed 2 November 2026. Windows and Linux, and an in-place upgrade from 5.3 or later, but for the original hMailServer's 5.7.Download 6.3.8 Documentation FAQ
  1. Support and discussion for hMailServer
  2. Running hMailServer
  3. Anti-spam & message filtering
  4. Viruses and dangerous attachments: ClamAV, custom scanners, the sandbox, sealed mail

Viruses and dangerous attachments: ClamAV, custom scanners, the sandbox, sealed mail

Scheduled Pinned Locked Moved Anti-spam & message filtering
securityadministrationlogslimitations
1 Posts 1 Posters 118 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ProgressiverobotP
    ProgressiverobotP
    Progressiverobot
    hMailServer Team
    wrote on last edited by chris
    #1

    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) calls the anti-virus action that strips attachments Remove all attachments and deliver the text (Delete infected attachments only in 6.3.6's Control Panel), and under it a message whose one part is an attachment, and an S/MIME message signed as one part, now arrive as the action's note alone, where every version to 6.3.6 delivered them as they arrived with what the scanner had found in them; a message the server cannot read is deleted and each of its recipients sent the "message deleted" notice whatever the two notify settings say, while an encrypted message, and one that is one text part, are delivered as they are. In the Control Panel the sidebar has a Virus scanning group, and Ctrl+K takes every old title to its page. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026) lets the Linux server reach clamd over its Unix socket: ClamAVHost takes the absolute path of clamd's LocalSocket, such as /var/run/clamav/clamd.ctl for Debian's and Ubuntu's clamav-daemon, which listens on nothing else by default, and ClamAVPort is then not used; no connection test is offered for it on Linux, so a test message and the log show the scan (ClamAV.md). See the 6.3.8 announcement.

    hMailServer does not scan for viruses itself. It hands each message to an engine you install (ClamAV, ClamWin or any command-line scanner) and acts on the answer, and nothing described here is enabled on a fresh install. This topic covers the three scanners, what happens when one finds something or cannot run, the blocked-attachment list, and what 6.3.4 added: the sandbox, and the handling of mail sealed end to end. The one thing to know first is the failure mode: a configuration that looks enabled and is inert. A scanner switched on with a wrong host or a missing executable does not refuse mail and does not disable itself; when every scanner has errored the verdict is NoVirusFound, which from the message's point of view is identical to having been examined and found clean. 6.3.4 fixed one such case in the custom scanner, described below.

    What runs, and when

    Scanning happens on the delivery side, not during the SMTP conversation: the message has already been accepted and spooled by the time any scanner sees it.

    Which messages are scanned. For SMTP, a message is flagged when the connecting IP's security range has the virus-protection option; both default ranges ("Internet" and "My computer") have it. For mail this server fetches over POP3 or IMAP, the flag is the external account's own "use anti-virus" setting. A flagged message larger than AntiVirus.MaximumMessageSize is not scanned at all, silently; the default is 0, no limit.

    Two passes. The whole spool file is scanned first; then every MIME attachment is written to a temporary file and scanned separately, which is what matters for a scanner that does not decode MIME itself. If the message cannot be parsed for the second pass, error HM6001 is reported and only the whole file was scanned; if one attachment cannot be written to the temp directory, HM6002 is reported and that attachment was not examined.

    Concurrency. At most 10 scans run at once (MaxRunningScanners). A thread that cannot get a slot waits up to 60 seconds and then scans anyway, writing Scanning message without an available virus scanner slot. to the debug log.

    The read-only overview. Spam & virus filtering → Virus scanning overview in the Control Panel (Windows only) answers the question the settings page cannot: will an infected message be caught here.

    The three scanners

    All three can be enabled at once. They run in the order ClamWin, custom, ClamAV, stopping at the first that reports a virus. A scanner that errors does not stop the others.

    ClamAV (clamd) ClamWin (clamscan.exe) Custom scanner
    Switch AntiVirus.ClamAVEnabled AntiVirus.ClamWinEnabled AntiVirus.CustomScannerEnabled
    Default off off off
    Reached by TCP socket, INSTREAM one process per file one process per file
    Settings AntiVirus.ClamAVHost (localhost), AntiVirus.ClamAVPort (3310) AntiVirus.ClamWinExecutable, AntiVirus.ClamWinDBFolder AntiVirus.CustomScannerExecutable
    "Infected" is a reply matching stream…: <name> FOUND exit code 1 exit code equal to AntiVirus.CustomScannerReturnValue
    Timeout ClamMinTimeout 15 s to ClamMaxTimeout 90 s ExternalProcessTimeout, 300 s ExternalProcessTimeout, 300 s
    Virus name reported the name clamd returned always Unknown always Unknown

    ClamAV. Install ClamAV, run freshclam to download signatures, run clamd listening on TCP 3310, set the host and port, and press Test ClamAV connection. The button does three things in order:

    1. It sends nPING and requires PONG, so "nothing is listening" is told apart from "something else is listening".
    2. It sends nVERSION and reports what answered.
    3. It streams a harmless sample and then the EICAR test string, both from memory, and requires the first to come back clean and the second FOUND.

    A success looks like ClamAV 1.4.2/27700/Mon Sep 8 09:12:11 2026. Result: stream: Eicar-Signature FOUND; a failure names the step, for example Unable to connect to ClamAV server at localhost:3310.

    The custom scanner. Any program that exits with a distinguishable code will do. Put %FILE% where the file to scan belongs; without it, the file name is appended as the single quoted argument. The Control Panel ships presets, all of them Windows programs:

    Preset Command line "Infected" exit code
    Microsoft Defender "C:\Program Files\Windows Defender\MpCmdRun.exe" -Scan -ScanType 3 -File "%FILE%" -DisableRemediation 2
    Sophos "C:\Program Files\Sophos\Sophos Anti-Virus\savscan.exe" -ss -archive "%FILE%" 3
    ESET "C:\Program Files\ESET\ESET Security\ecls.exe" "%FILE%" 50
    Bitdefender "C:\Program Files\Bitdefender\Endpoint Security\bdscan.exe" "%FILE%" 1
    Kaspersky "C:\Program Files (x86)\Kaspersky Lab\Kaspersky Endpoint Security\avp.com" SCAN "%FILE%" 2

    The 6.3.4 fix: a bare %FILE%. CHANGELOG records that a custom scanner whose command line holds a bare, unquoted %FILE% was handed the message file's path cut at its first space, and the default data directory, under C:\Program Files, has one. The scanner therefore scanned no file, answered with an exit code other than the virus one, and the message was delivered as clean. Since 6.3.4 a %FILE% outside double quotes is replaced by the path in quotes. One already inside them, "%FILE%" as the documented examples above write it, was not affected and is replaced as before. If you run an earlier release with a command line of your own, check it for an unquoted %FILE%. The same fix removes a trailing backslash from ClamWin's database and temporary folders, which escaped the closing quote of --database="..." and took the file to scan with it.

    The service account must be able to run the scanner. A new 6.3.4 installation on Windows runs the service as NT SERVICE\hMailServer by default; an upgrade keeps the account it had, LocalSystem unless the installer's page is answered otherwise (docs/ServiceAccount.md; the wiki's "LocalSystem by default" describes earlier releases and upgraded servers). Under the virtual account a custom scanner or ClamWin runs as that account: it reads the message in the temp folder, which is granted, and its own program and signatures, which the Users group can normally read; a scanner that needs more has to be granted it (Installing on Windows covers the account and its grants). Whichever account runs yours, the executable, its database directory and the temp directory must all be reachable by it. The symptom of getting it wrong is Unable to launch the virus scanner… reported as HM5406, once per message.

    For an engine with no command-line interface, the wiki points to an OnAcceptMessage event script or the HTTP filter hook. If you edit hm_settings by hand, note that the custom scanner's return value is stored under the misspelled name customviursscannerreturnvalue.

    Testing it end to end

    The test buttons check the scanner. To check the pipeline, send yourself a message with the EICAR test file attached and watch the application log:

    Virus found in message from [email protected]. Taking actions
    SMTPDeliverer - Message 4711: Message will be deleted (contained virus Eicar-Signature).
    

    Two things spoil that test on Windows. The host antivirus eats the EICAR file before hMailServer sees it, so exclude the mail store and the temp directory from real-time scanning. And your own outbound mail is not scanned by this server if it never comes back in through SMTP from an unauthenticated range, so send the test from an external address.

    What happens when a virus is found

    AntiVirus.Action What happens
    Delete entire e-mail (0, the default) The message is delivered to nobody. Logged as Message will be deleted (contained virus X).
    Delete infected attachments only (1; Remove all attachments and deliver the text in 6.3.7's Control Panel) The message is rebuilt, not edited: the first text part is kept, everything else is discarded, the VIRUS_ATTACHMENT_REMOVED server message is prepended to the body and the subject is prefixed with the VIRUS_FOUND message. Logged as Message attachments stripped (contained virus X). Since 6.3.7 a message whose one part is an attachment arrives as the note alone, where every version to 6.3.6 delivered it as it arrived, and one the server cannot read is deleted, each recipient sent the "message deleted" notice whatever the two notify settings say

    Understand the rebuild before you choose it: an HTML alternative, inline images and every clean attachment go with the infected one. AntiVirus.NotifySender and AntiVirus.NotifyReceiver are both off by default, and the wiki's advice is to leave them off: the sender address on a virus is virtually always forged, so a notification is backscatter.

    When a scanner cannot run

    Setting Default Meaning
    AVFailAction 0 0 delivers the message anyway. 1 never delivers unscanned mail
    AVFailRetryMinutes 15 Minutes between scan attempts while a message is held
    AVFailMaxHolds 16 Holds before the message is returned to its sender. 0 tells the sender immediately

    They are on Anti-virus settings → General, card When a scanner cannot run. The wiki describes them as stored in hMailServer.INI; since 6.3.4 the database is the settings store and a [Settings] line edited in the file is put back, so change them in the Control Panel, over REST (PUT /api/v1/settings/ini/{name}) or, on Linux, with hmailserver --set-setting NAME=VALUE. At the defaults, AVFailAction 1 gives a message about four hours to be scanned before its sender is told. The hold counter is the policy's own, not the message's try counter, because incrementing that would make the pass that finally scans the message skip DKIM signing. It lives in memory, so a restart gives every held message a fresh budget, and it is bounded at 100,000 tracked messages; beyond that messages are still held, never delivered unscanned, and HM6195 is reported. Every scanner error is reported as HM5406 with the failing scanner's own text.

    Blocked attachments

    Spam & virus filtering → Blocked attachments refuses files by name pattern. The master switch is AntiVirus.EnableAttachmentBlocking, default off. The wiki's starting list:

    *.exe   *.scr   *.pif   *.bat   *.cmd   *.com   *.vbs
    *.js    *.jse   *.wsf   *.wsh   *.hta   *.jar   *.msi
    *.msp   *.cpl   *.lnk   *.reg   *.ps1   *.iso   *.img
    

    The attachment is not deleted. Its file name has .txt appended and its content is replaced by the ATTACHMENT_REMOVED server message, which names the original file through the %MACRO_FILE% macro, so the recipient receives invoice.exe.txt containing an explanation. Matching is a case-insensitive wildcard over the declared file name. It does not look inside archives and cannot see the real type of a file whose extension lies: it is a policy control, not a scanner.

    Since 6.3.4 the rewrite is logged. A rewritten message produces VirusScanner - Message 1234 from [email protected]: the attachment(s) invoice.exe matched the blocked-attachment list. Their content has been replaced with a notice and the message rewritten. Before this the rewrite left no record anywhere but inside the message itself.

    Sealed mail: what the list and the scanner do with it

    Since 6.3.4. A message encrypted end to end, S/MIME or PGP/MIME, is opaque to the server, which decides that from the body, never from the Content-Type label, so a message only labelled encrypted is blocked, stripped and scanned like any other. What opaque means exactly, and what the rest of the server does with such a message, is in the topic on end-to-end encryption and sealed mail. For the list and the scanner, none of it is a setting:

    • The blocked-attachment list never rewrites an opaque message. In 6.3.3 and earlier blocking *.asc, *.p7m, *.p7s or *.* replaced the content of every sealed message with the notice, with no log line, and the plaintext existed nowhere else. It is now delivered as it arrived, and the application log says it was not checked against the list. A signed message is checked like any other, with its detached signature left alone.
    • The scanner still scans it, and what it examines is ciphertext, so a clean result is not a verdict on the message; the log says its content COULD NOT BE EXAMINED for viruses. It is deliberately not treated as a scanner failure, so a server with AVFailAction 1 does not hold every encrypted message it receives; a policy that unscannable mail must not be delivered belongs in a rule or a Sieve script, not the scanner.
    • The "delete attachments" action never strips an encrypted message. When the scanner objects to one, the message is left as it arrived and the log ends Set the anti-virus action to delete the message if such a message must not be delivered. That is not a quiet pass: the message still carries what the scanner objected to. To 6.3.6 this held for every opaque message; since 6.3.7 an S/MIME message signed as one part (application/pkcs7-mime holding signed-data, which is opaque but not encrypted) is replaced by the action's note, as any other single-part attachment is.

    The sandbox

    Since 6.3.4 (schema 6091). ClamAV says whether a file is known to be bad. What an unknown file does when it is opened takes a sandbox, a service outside this server which you run or subscribe to. It does nothing until you name one: SandboxEnabled is off, and cannot be saved on while SandboxSubmitUrl or SandboxVerdictUrl is empty. Both addresses must be https, or plain http to this machine.

    After the anti-virus scan and before the rules, a message that no signed-in user of this server submitted, with an attachment whose extension or media type is in SandboxTypes, is held: in no mailbox, not in the quarantine, and in nobody's digest. The default types are:

    exe,dll,scr,js,jse,vbs,wsf,hta,msi,bat,cmd,ps1,jar,lnk,iso,img,docm,xlsm,pptm,
    doc,xls,ppt,rtf,pdf,zip,7z,rar
    
    The sandbox says What happens
    every file clean delivered, with an X-hMailServer-Sandbox header reading clean (<n> file(s), <seconds>s)
    any file malicious, or suspicious at or above SandboxScoreThreshold (70) quarantined with the verdict as the reason; returned to its sender with 5.7.1 while QuarantineEnabled is off
    an error, once every file has answered, or no answer within SandboxTimeoutMinutes (15) SandboxTimeoutAction: deliver (0, the default) delivers with a header saying so; bounce (1) returns it to its sender

    The contract. One POST per file to SandboxSubmitUrl as multipart/form-data with four fields (file, filename, sha256, message_id), then a GET to SandboxVerdictUrl every SandboxPollSeconds (30), answered with JSON such as {"state":"done","verdict":"clean","score":3,"detail":"opened, nothing happened"}. With SandboxToken set, every request carries Authorization: Bearer <token>; the token is not in the backup archive. No vendor adapter is shipped. The document notes that a service which shares what it is sent, as VirusTotal shares uploads with its subscribers, is a place the attachments of the mail you receive go.

    What is exempt. What your own signed-in users submit (authenticated SMTP, the webmail, the send API) is not uploaded unless SandboxInternalMail is on. The document states the threat model of that default: a stolen password used to send attachments to colleagues is not examined by the sandbox, though ClamAV, the blocked-attachment list and compromised-account detection still apply.

    Limits. An attachment larger than SandboxMaxSizeKB (20480) is not submitted. A message with more files to submit than SandboxMaxFiles (10) is not held, and SandboxTimeoutAction decides it at once. Archives are submitted whole; links are not opened anywhere. A clean or malicious verdict is remembered by the file's SHA-256 for SandboxCacheHours (24), server-wide.

    What the administrator sees. GET /api/v1/sandbox/held lists what is held; POST /api/v1/sandbox/held/{queue_id}/release delivers without the verdict and DELETE /api/v1/sandbox/held/{queue_id} discards, both on the audit trail. The Control Deck's queue page has a Held for a sandbox box, and hmctl queue list has a held column. The settings are on the Control Panel's Anti-virus page, Sandbox tab (Windows only), and on PUT /api/v1/settings.

    Rules, and the message store

    Since 6.3.4 the mail flow rules can match the attachment's name and, in the outbound content policy, its type read from its bytes, so a rule can hold or refuse what the blocked-attachment list would only rename; that is in the topic on mail flow rules. The message store options added in 6.3.4 change nothing for a scanner: a message is scanned as plain RFC 822 in the queue and only placed in the mailbox in its stored form afterwards. A scanner pointed at the data directory from outside the server reads a compressed or encrypted container, not a message.

    Error codes

    Code Meaning
    HM5406 An enabled scanner errored; the detail names the scanner and the failure
    HM6001 The message could not be parsed, so only the whole file was scanned
    HM6002 An attachment could not be written to the temp directory for scanning
    HM6195 100,000 messages are already held for want of a scan; further holds are not counted
    HM7272 The sandbox called a message malicious and the quarantine could not store it; it is held again, never delivered

    Where to read more

    • Wiki: https://gitlab.com/hmailserver/hmailserver/-/wikis/Stopping-Viruses
    • https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Sandbox.md
    • https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SealedMail.md
    • Public documentation: https://www.progressiverobot.com/hmailserver-documentation/#11-stopping-viruses, https://www.progressiverobot.com/hmailserver-documentation/#111-clamav and https://www.progressiverobot.com/hmailserver-documentation/#112-blocked-attachments
    • Upgrading to 6.3.4 and the 6.3.4 security announcement
    1 Reply Last reply
    0

    Hello! It looks like you're interested in this conversation, but you don't have an account yet.

    Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

    With your input, this post could be even better 💗

    Register Login
    Reply
    • Reply as topic
    Log in to reply
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes


    hMailServer Community

    The community support forum for hMailServer — the free, open-source mail server for Windows and Linux — maintained by Progressive Robot Ltd. The software is AGPL-3.0 and stays that way; this is where it is discussed, debugged and documented.

    The software

    • Documentation
    • Downloads
    • hMailServer 6.3
    • Source on GitLab

    Getting help

    • Forum rules
    • About this forum
    • Support plans
    • Pay monthly support
    • Talk to Progressive Robot

    Legal

    • Privacy policy
    • Terms and conditions
    • Cookie policy

    Progressive Robot Ltd · 220 Chester Business Park, Heronsway, Chester, Cheshire CH4 9GB, United Kingdom · +44 (0)1244 911212 · [email protected] · VAT 506152326

    Powered by NodeBB

    • Login

    • Don't have an account? Register

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Popular
    • Tags
    • Users
    • Groups
    • Documentation
    • Downloads
    • Report a bug
    • GitHub mirror
    • Paid support