Clicky

20200208

hMailserver: reject emails that have long subjects

Some people paste long strings in the Subject field of emails. The maximum number of characters of the Subject field is 998 characters but can be tweaked to more. It does not make sense to have more than ~160 characters so lets reject messages that have long Subject fields.

In hMailserver we can reject those emails very simply. In the OnSMTPData sub the Subject field is available and we can measure the amount of characters (length):

Sub OnSMTPData(oClient, oMessage)

    subjectLength = len(oMessage.Subject)


    if subjectLength > 160 then
        Eventlog.Write("OnAcceptMessage: email rejected because of Subject = " &  subjectLength & " characters (>160). From: " & oMessage.FromAddress)
        result.value=1
    end if

end sub

When a subject field of an email is longer than 160 characters, the event will be logged in the hMailserver logfile and the email will be rejected.

4144    "2020-02-08 09:02:37.138"    "OnAcceptMessage: email rejected because of Subject = 236 characters (>160). From: email@sender.com"

Also, the sender gets an email that the email is rejected:


Your message did not reach some or all of the intended recipients.

      Subject:     RE: 1234567890RE: 1234567890RE: 1234567890RE: 1234567890RE: 1234567890RE: 1234567890RE: 1234567890RE: 1234567890RE: 12345678901234567890
      Sent:  2/8/2020 9:03 AM

The following recipient(s) cannot be reached:

      Email Sender (email@sender.com) on 2/8/2020 9:03 AM
            554 Rejected

hMailserver geolocation blacklist

The purpose of the next scripts is twofold:
  1. Block email sessions of email servers that are on the blacklist
  2. Automatically create a blocking firewall rule in case of bad behaving or misconfigured remote email servers
Let start with requirement #1: We use here the free gelocation service (max 20 lookups per minute) of https://extreme-ip-lookup.com. They provide different IP-to-Geo lookup methods. Here we use the JSONP method:

The IP address of the remote email server is available in the OnClientConnect subroutine of the hMailserver EventHandler.vbs script. The code to obtain the remote emailserver's IP address is this:

Sub OnClientConnect(oClient)

    Const BlackList=" AR BG BO BR CC CM CO GA IN IQ IR KE KZ MA ME MX RO RO RU TH TH TK TW UA VN "
      
    geoLocation = IPtoGeo(oClient.ipaddress)


    if len(geoLocation) = 2 and geoLocation <> "XX" then
        if Instr(Blacklist, geoLocation) > 0 then
            Eventlog.Write("[Blacklist] OnClientConnect: " & oClient.ipaddress & " - " & geoLocation & " is in the Blacklist and the session is disconnected.")
          
            '--- Reject message...
            Result.Value = 1   
        end if
      
    end if

End Sub


We use a seperate function (IPtoGeo) to map the IP address to a countrycode. The function IPtoGeo looks like this:

function IPtoGeo(IPaddr)

    Const countryString = """countryCode"".*"   
   
    geoLocation = "XX"
   
    if Instr(IPaddr,"192.168.") <> 1 and Instr(IPaddr,"10.") <> 1 and Instr(IPaddr,"127.") <> 1 then
   
        lookupGeolocation = "https://extreme-ip-lookup.com/json/" & IPaddr & "?callback=getIP"
       
        Set objHTTP = CreateObject("Msxml2.XMLHTTP")
        objHTTP.open "GET", lookupGeolocation, False
        objHTTP.send
        returnString = Cstr(objHTTP.responseText)

        set objRegexp = new RegExp
        objRegexp.pattern = countryString
        objRegexp.ignoreCase = true
        objRegexp.global = false
        set matches = objRegexp.execute(returnString)
       
        if matches.count = 1 then
            s = matches(0).value
            t = split(s,":")
            u = split(t(1), chr(34))
            geoLocation = u(1)
        end if
       
    end if

    IPtoGeo = geoLocation

end function


When an IP address is mapped to a country code that is the blacklist (Const BlackList), the email session is disconnected (Result.Value = 1) and the hMailserver eventlog (hmailserver_events.log) shows:

4376    "2020-02-08 03:36:46.319"    "[Blacklist] OnClientConnect: 79.124.62.14 - BG is in the Blacklist and the session is disconnected."

It happens somtimes that remote email servers start retrying or even hammering the hMailserver after a rejected session. E.g. I found a remote email server continuously trying to connect twice per minute. We want to block those connections in an earlier stage.

So for requirement #2 we use a small Powershell script to create a firewall block rule. We use Powershell because the regular expressions in VBscript are slow and Powershell provides the -Match method and an easy method to set a firewall rule.

$maxAttempts = 10
$logFile = get-content "d:\hMailserver\logs\hmailserver_events.log"
$today = (get-date).ToString("yyyy-MM-dd")
$searchBase = ($logFile -match $today)

$ip = $args[0]

if ($ip -match "(?:[0-9]{1,3}\.){3}[0-9]{1,3}")
{
    $hammerCount = $searchBase -match $ip
    if ($hammerCount.count -GT
$maxAttempts) {
        $ruleDate = (get-date).toString("yyyy-MM-dd")
        $blockName = "hammerBlock ($IP, $ruleDate)"
        write-host "*** Setting rule: $blockName"
        $ruleExists = Get-NetFirewallRule -DisplayName $blockName -erroraction SilentlyContinue
        if ($ruleExists) {
            Remove-NetFirewallRule -DisplayName $blockName
        }
        New-NetFirewallRule -DisplayName $blockName -Direction Inbound -Action Block -RemoteAddress $IP | out-null
    }
}   


The powershell script (hammerBlock.ps1) is called in the OnClientConnect sub:

Sub OnClientConnect(oClient)

    dim wsh

    Const BlackList=" AR BG BO BR CC CM CO GA IN IQ IR KE KZ MA ME MX RO RO RU TH TH TK TW UA VN "

    set wsh = CreateObject("wscript.shell")
       
    geoLocation = IPtoGeo(oClient.ipaddress)
    if len(geoLocation) = 2 and geoLocation <> "XX" then
        if Instr(Blacklist,geoLocation) > 0 then
            Eventlog.Write("[Blacklist] OnClientConnect: " & oClient.ipaddress & " - " & geoLocation & " is in the Blacklist and the session is disconnected.")
           
            '--- Run the Firewall block script from here...
            runString = "powershell -file ""c:\scripts\hammerBlock.ps1"" " & oClient.ipaddress
            wsh.run runString,0,true

           
            '--- Disconnect...
            Result.Value = 1    
        end if
       
    end if

End Sub


When a remote email server, that is in the blocklist, tries to connect more than 10 times on one day, a firewall block rule is created. The rule looks like this:


I know that there are many more methods to block sessions based on geolocation. Most of them are quite hard to configure and maintain. With the scripts above, all work is executed in the hMailserver ecosystem. This also allows easy management and migration to other hMailserver instancesor adapt the scripts here for different purposes.


Real Time Web Analytics