Detecting failure after first delivery attempt

Use this forum if you have problems with a hMailServer script, such as hMailServer WebAdmin or code in an event handler.
Post Reply
User avatar
Steve Gibson
New user
New user
Posts: 6
Joined: 2024-05-31 04:38
Contact:

Detecting failure after first delivery attempt

Post by Steve Gibson » 2024-05-31 05:34

Hey folks,

I'm hoping to get some help from those here who have experience with the scripting side of hMailServer. Having read through this forum extensively looking for the other answers, I know the likely suspects. :)

I've implemented an email confirmation loop which sends an email to someone who is wishing to register with my site ([removed]). The email they receive contains a link that brings them back to choose which email lists they wish to join.

The problem is that if the user wonders why they didn't receive the verification email, I'd like to be able to tell them what's going on with their email as seen from my end.

But... as we know, soft bounces (4xx's) are retained in the delivery queue and will remain there for quite awhile. Hard bounces (5xx's) fail immediately. So hard bounces can be detected by monitoring the sending account for failures. One way I can see to catch soft bounces is to watch the delivery queue. Constantly polling the queue, which will almost always be empty, is inelegant. The other thing I noticed was that Rule processing has a "Delivery attempts" trigger. The docs say: “Delivery attempts - 1 the first time the message is delivered, 2 on the second attempt and so on.”

Does anyone know whether this means that this trigger will fire upon the first FAILURE?

The other (horrible and impractical) thing I could do would be to run a separate domain with hMailServer configured for no delivery retries... But that's really no practical. I don't suppose there's any way to make one account on the system have zero retries?

Any thoughts or bright ideas would be more than welcome! Thanks, all!

/Steve.

palinka
Senior user
Senior user
Posts: 4610
Joined: 2017-09-12 17:57

Re: Detecting failure after first delivery attempt

Post by palinka » 2024-05-31 06:50

You could try this script that forces messages with a certain header (eg. "X-hMailServer-Priority = Confirmation") to the top of the queue. Then it would retry immediately.

viewtopic.php?p=218774

palinka
Senior user
Senior user
Posts: 4610
Joined: 2017-09-12 17:57

Re: Detecting failure after first delivery attempt

Post by palinka » 2024-05-31 07:07

Or maybe you can just change the delivery settings to try 10 times with 1 minute in between. You would get the failure notice after 10 minutes, but at least it would try again. This would be helpful against gray listing, but not network issues. Also, it may mess up your regular mail delivery - there's a reason there's space between delivery attempts.

Another thing you could try - and I'm not even sure if this would work - is to create a route for those messages, but the destination would be yourself. Routes can be configured for the number of delivery attempts like above (eg 10 tries in 10 minutes). If this doesn't work (pointing route to self), then setting up a 2nd hmailserver for this purpose certainly would work.

You requested to be notified when messages get stuck, but I think its more important to try to get the message through quickly. If you just want to be notified right away, then I made a powershell script that reads the delivery queue here: https://hmailserver.com/forum/viewtopic.php?f=7&t=42057

You can run that from task scheduler every minute. Modify the code to send a notification if $_.Tries -gt 1. Let me know if you need help with the code.

Or you could script a handler that reads the database for the same information, then sends a notification if retries > 1.

Code: Select all

SELECT * FROM `hm_messages` WHERE `messagecurnooftries` > 1;
I guess the question is what do you plan to do with this information? If it can't be delivered, and its some random person you can't contact by alternative means, then what's the point? ¯\_(ツ)_/¯

User avatar
SorenR
Senior user
Senior user
Posts: 6364
Joined: 2006-08-21 15:38
Location: Denmark

Re: Detecting failure after first delivery attempt

Post by SorenR » 2024-05-31 15:25

Steve Gibson wrote:
2024-05-31 05:34
Hey folks,

I'm hoping to get some help from those here who have experience with the scripting side of hMailServer. Having read through this forum extensively looking for the other answers, I know the likely suspects. :)

I've implemented an email confirmation loop which sends an email to someone who is wishing to register with my site ([removed]). The email they receive contains a link that brings them back to choose which email lists they wish to join.

The problem is that if the user wonders why they didn't receive the verification email, I'd like to be able to tell them what's going on with their email as seen from my end.

But... as we know, soft bounces (4xx's) are retained in the delivery queue and will remain there for quite awhile. Hard bounces (5xx's) fail immediately. So hard bounces can be detected by monitoring the sending account for failures. One way I can see to catch soft bounces is to watch the delivery queue. Constantly polling the queue, which will almost always be empty, is inelegant. The other thing I noticed was that Rule processing has a "Delivery attempts" trigger. The docs say: “Delivery attempts - 1 the first time the message is delivered, 2 on the second attempt and so on.”

Does anyone know whether this means that this trigger will fire upon the first FAILURE?

The other (horrible and impractical) thing I could do would be to run a separate domain with hMailServer configured for no delivery retries... But that's really no practical. I don't suppose there's any way to make one account on the system have zero retries?

Any thoughts or bright ideas would be more than welcome! Thanks, all!

/Steve.
Any association to grc.com?

I use this:

Code: Select all

Sub OnDeliveryFailed(oMessage, sRecipient, sErrorMessage)
    Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")
    Dim oNDR, oMatch, oMatchCollection, strRegEx, strResult, strFilename
    Dim EventLogX : Set EventLogX = New LogWriter
    EventLogX.LogFile = "deliveryfail"
    '
    '   Not all events need action ...
    '
    strRegEx = "(Message delivery cancelled during ((virus scanning)|(global rules)|(OnDeliverMessage-event)))|" & _
               "(Delivery cancelled by OnDeliveryStart-event)"
    If Lookup(strRegEx, sErrorMessage) Then Exit Sub
    '
    '   Logging ...
    '
    EventLogX.Write( LPad("DeliveryFailed", 15, " ") & vbTab & "sRecipient = " & sRecipient )
    EventLogX.Write( LPad("DeliveryFailed", 15, " ") & vbTab & "sErrorMessage = " & sErrorMessage )
    '
    '   NDR - Remote server replied -
    '
    strRegEx = "^(?:.*Remote server replied:\s)([0-9]{3})(?:\s.*)$"
    Set oMatchCollection = oLookup(strRegEx, sErrorMessage, False)
    For Each oMatch In oMatchCollection
        If oMatch.SubMatches.Count > 0 Then
            strResult = oMatch.SubMatches(0)
            '
            '   Return mail with message
            '
            If oFSO.FileExists(oMessage.Filename) Then
                Set oNDR = CreateObject("hMailServer.Message")
                If Lookup("(\@home\.arpa)", oMessage.FromAddress) Then oNDR.AddRecipient "VOID", oMessage.FromAddress
                oNDR.AddRecipient "VOID", "postmaster@home.arpa"
                oNDR.HeaderValue("To") = oMessage.HeaderValue("To")
                oNDR.HeaderValue("hMailServer-Clone") = "YES"
                oNDR.Subject = "** FAILED DELIVERY ** " & oMessage.Subject
                oNDR.Body = sErrorMessage
                oNDR.Attachments.Add(oMessage.Filename)
                oNDR.Save
                Set oNDR = Nothing
            Else
                EventLogX.Write( LPad("DeliveryFailed", 15, " ") & vbTab & "oMessage.Filename = ** DELETED **" )
            End If
        End If
    Next
    Set EventLogX = Nothing
    Set oMatch = Nothing
    Set oMatchCollection = Nothing
End Sub
PS... Supporting code not included.
SørenR.

Woke is Marxism advancing through Maoist cultural revolution.

User avatar
katip
Senior user
Senior user
Posts: 1176
Joined: 2006-12-22 07:58
Location: Istanbul

Re: Detecting failure after first delivery attempt

Post by katip » 2024-05-31 16:21

SorenR wrote:
2024-05-31 15:25
Any association to grc.com?
Very owner i think.
Yet another renown Steve on our forum after so many years, along Steve from Sanesecurity.
Welcome..
Katip
--
HMS 5.7, MariaDB 10.4.10, SA 4.0.0, ClamAV 0.103.8

User avatar
RvdH
Senior user
Senior user
Posts: 3339
Joined: 2008-06-27 14:42
Location: The Netherlands

Re: Detecting failure after first delivery attempt

Post by RvdH » 2024-05-31 16:33

Maybe you should have started to make him aware this is no longer a maintained mailserver solution
https://www.hmailserver.com/state

VbScript support will be dropped from future windows releases, so not sure if it wise to to pick and choose software and techniques that are not really future proof
CIDR to RegEx: d-fault.nl/cidrtoregex
DNS Lookup: d-fault.nl/dnstools
DKIM Generator: d-fault.nl/dkimgenerator
DNSBL Lookup: d-fault.nl/dnsbllookup
GEOIP Lookup: d-fault.nl/geoiplookup

User avatar
Steve Gibson
New user
New user
Posts: 6
Joined: 2024-05-31 04:38
Contact:

Re: Detecting failure after first delivery attempt

Post by Steve Gibson » 2024-05-31 19:52

SorenR wrote:
2024-05-31 15:25
Any association to grc.com?
Yep. GRC stands for "Gibson Research Corporation" and I'm that Steve Gibson.

I've been in LOVE with hMailServer for many many years. What a lovely piece of work. It's really the ideal of Open Source software at its best. I'm sorry Martin could not continue, but the down side of Open Source is that it's a pretty thankless passion. I would GLADLY pay the use of this excellent piece of software.

So... I'm very glad that these forums exist. Until just recently HMS's built-in features did everything I needed. (And I just updated to the latest production build since I wanted to get TLS v1.3 support from its updated OpenSSL.) But I just needed to do some scripting for the first time ever... and that was equally painless and gratifying. In the OnAcceptMessage for a specific account, I'm performing an XMLHTTP query to our back-end database to see whether the sender's email is known to our system, so a simple and clean whitelisting system. And it's all working beautifully.

The question that brought me here was whether or not there was any way to detect the FIRST (immediate) failure of delivery so that a near real time email confirmation loop could inform someone that we encountered delivery trouble.

SorenR: Thanks for reposting that script. I think I encountered it previously when searching here for answers. But, unfortunately, isn't the “OnDeliveryFailed” event only triggered when HMS finally gives up on delivering the message? When I'm looking for is news of the failure of its first (or any) attempt to deliver.

I know I could turn on SMTP logging and monitor the log, but we have a VERY active server and logging all SMTP transactions would be a nightmare (and it's also about the worst kludge imaginable! :)

As I mentioned in my first post, there's a "Delivery Attempts" rule match... so that might be where a solution lies. If I can find something I'll post my final solution here!

Thanks everyone!

User avatar
Steve Gibson
New user
New user
Posts: 6
Joined: 2024-05-31 04:38
Contact:

Re: Detecting failure after first delivery attempt

Post by Steve Gibson » 2024-05-31 20:59

UPDATE: I forced a transient failure by asking HMS to send email to "bingo@bangozoom.com" where "bangozoom" has no DNS resolution. Checking the Delivery Queue showed the message lodged there with '1' delivery attempt... but the RULE I had did not trigger. So my guess is that Rules are only triggered on delivery of a message to an account (that makes sense) so the Rule's "Delivery Attempts" match feature would be used to show how many attempts were made before either success or final failure.

So my conclusion is that I'm going to need to monitor the delivery queue through HMS's COM API. I dislike any sort of polling solution, but there doesn't appear to be any alternative since none of the various events reflect alterations of the queue. I tried dumping the queue during "OnAcceptMessage" and it sometimes, but not always, worked.

User avatar
mattg
Moderator
Moderator
Posts: 22464
Joined: 2007-06-14 05:12
Location: 'The Outback' Australia

Re: Detecting failure after first delivery attempt

Post by mattg » 2024-06-01 04:40

Steve Gibson wrote:
2024-05-31 20:59
UPDATE: I forced a transient failure by asking HMS to send email to "bingo@bangozoom.com" where "bangozoom" has no DNS resolution.
That should retry.


I catch things like 'address@gmail.com.au' because there is no dns match for that misspelled domain
I count retries and catch then at 1 hour, then send a message to the sender, asking them to confirm the address.
The original message is resent for the limit set in retries (more than one day for me).

The idea is that a domain without DNS records may just be a temporary failure.

Oh, and welcome Steve.
Love your work.
Just 'cause I link to a page and say little else doesn't mean I am not being nice.
https://www.hmailserver.com/documentation

User avatar
SorenR
Senior user
Senior user
Posts: 6364
Joined: 2006-08-21 15:38
Location: Denmark

Re: Detecting failure after first delivery attempt

Post by SorenR » 2024-06-01 12:06

Steve Gibson wrote:
2024-05-31 19:52
SorenR wrote:
2024-05-31 15:25
Any association to grc.com?
Yep. GRC stands for "Gibson Research Corporation" and I'm that Steve Gibson.
Welcome, I've been a follower of your work since Code Red broke out back in the day when I lived in Singapore. Your SpinRite has saved my a$$ on more than one occation and I still use ShieldsUp to check firewalls and routers :mrgreen:

Btw, do you still write all your Windows code in Assembler?

Back to issue ... There are two cases delivery will fail; 1 - Port closed/DNS not resolving and 2 - Receiving server says so... and this open a can of worms ;-) There can be 1,000 reasons why a server could claim a failed delivery.

My code focuses on when recipient server tells me.
SørenR.

Woke is Marxism advancing through Maoist cultural revolution.

User avatar
Steve Gibson
New user
New user
Posts: 6
Joined: 2024-05-31 04:38
Contact:

Re: Detecting failure after first delivery attempt

Post by Steve Gibson » 2024-06-01 23:56

SorenR wrote:
2024-06-01 12:06

Welcome, I've been a follower of your work since Code Red broke out back in the day when I lived in Singapore. Your SpinRite has saved my a$$ on more than one occation and I still use ShieldsUp to check firewalls and routers :mrgreen:

Btw, do you still write all your Windows code in Assembler?
Yep... All apps and server-side code (everything, actually) is still (and likely always will be) 100% assembler. It's not that it really makes any sense these days, but I've been coding in assembler for my entire life, so it's where I'm most comfortable. And the efficiencies of have only very small and tight code everywhere do add up. For example, I'm able to do so much with a single server where other solutions might require a rack. But, mostly, it's just what I most enjoy. I code because I love it. SpinRite was and is pure assembler, and, for example, all of the packet management behind ShieldsUP! is also assembler.

And... Of course... I'm now in the process of working out the details of calling the HMS COM API ... From assembler! <g>

I'm delighted that SpinRite has been useful to you in the past, and if you happen to own v6.0, I've recently finished a 3.5 year project of rewriting most of its code to create v6.1. Even though v6.0 was released 20 years ago (in 2004), v6.1 is a free upgrade to all v6.0 owners. My plan is to make v7.0 so good that no one will be able to resist upgrading to that one! :)

User avatar
SorenR
Senior user
Senior user
Posts: 6364
Joined: 2006-08-21 15:38
Location: Denmark

Re: Detecting failure after first delivery attempt

Post by SorenR » 2024-06-02 01:48

Steve Gibson wrote:
2024-06-01 23:56
SorenR wrote:
2024-06-01 12:06

Welcome, I've been a follower of your work since Code Red broke out back in the day when I lived in Singapore. Your SpinRite has saved my a$$ on more than one occation and I still use ShieldsUp to check firewalls and routers :mrgreen:

Btw, do you still write all your Windows code in Assembler?
Yep... All apps and server-side code (everything, actually) is still (and likely always will be) 100% assembler. It's not that it really makes any sense these days, but I've been coding in assembler for my entire life, so it's where I'm most comfortable. And the efficiencies of have only very small and tight code everywhere do add up. For example, I'm able to do so much with a single server where other solutions might require a rack. But, mostly, it's just what I most enjoy. I code because I love it. SpinRite was and is pure assembler, and, for example, all of the packet management behind ShieldsUP! is also assembler.

And... Of course... I'm now in the process of working out the details of calling the HMS COM API ... From assembler! <g>

I'm delighted that SpinRite has been useful to you in the past, and if you happen to own v6.0, I've recently finished a 3.5 year project of rewriting most of its code to create v6.1. Even though v6.0 was released 20 years ago (in 2004), v6.1 is a free upgrade to all v6.0 owners. My plan is to make v7.0 so good that no one will be able to resist upgrading to that one! :)
IIRC SpinRite 6.0 was priced around $89 in 2005 when I got my license.

Regarding the "Delivery Attempts" rule criteria, I have two mailservers (Primary and BackupMX) on the same LAN addressing different routers (4G ISP and Fiber ISP) and I use this criteria to select an alternative route for delivery in the event of network error. LAN, Servers and Routers are all protected by battery backups.

Rule: AND
Criteria 1: Delivery attempts > 4
Criteria 2: Custom header "Received" RegEx "(?i:^.*\s(!ESMTP|!ESMTPS|ESMTPA|ESMTPSA)\s.*$)"
Action 1: Send using route "other route"

I could have used:
Action 1: Run function "DeliveryError"

and define a "Sub DeliveryError(oMessage)" code stub in EventHandlers.xx
SørenR.

Woke is Marxism advancing through Maoist cultural revolution.

User avatar
Steve Gibson
New user
New user
Posts: 6
Joined: 2024-05-31 04:38
Contact:

Re: Detecting failure after first delivery attempt

Post by Steve Gibson » 2024-06-20 21:51

Everyone...

I wanted to drop by here to thank everyone for their thoughts and input, and to let everyone know, just for the record, how my quest to detect message sending trouble turned out.

The TL;DR version is that I got far more than I ever expected to. My code/system can detect remote email server 400 and 500 errors immediately even though I'm unable to monitor the encrypted dialog between my hMailServer and the remote server.

The key was hMailServer's COM API. Though it took some work, I created the definition headers required to access the hMailServer COM interface from assembly language (since, we as know, x86 assembler is my own "native" programming language.) This allowed me to (a) monitor hMailServer's delivery queue in real time and (b) selectively delete any items from the queue.

The breakthrough, was the discovery that immediately upon a remote email server's rejection — for whatever reason — during hMailServer's attempt to send email to a bad address or a “full” mailbox, hMailServer places an email addressed from its “mailer-daemon” to the attempted sending account (in my case “mail-authenticate”) into the delivery queue. And that email I'm able to see immediately! — This I'm able to immediately detect and act upon a failed delivery while the user is still at my submission form.

I introduced a maximum 5-second wait after the user submits their email address to give this time to happen, if it's going to. And then some tricky, JavaScript-free, CSS that allows me to display a notice to the user during the 5 seconds we're waiting to see whether the user's email immediately bounces. In my testing this always happens within one or two seconds. The tricky CSS allows that pending wait notice to be removed either once 5 seconds have elapsed or the outbound email was rejected.

Anyone who's interested of curious may play with this at https://www.grc.com/mail.htm where it's all running.

So, again, thanks for the various pointers and suggestions!

User avatar
RvdH
Senior user
Senior user
Posts: 3339
Joined: 2008-06-27 14:42
Location: The Netherlands

Re: Detecting failure after first delivery attempt

Post by RvdH » 2024-06-21 07:54

Steve Gibson wrote:
2024-06-20 21:51
Everyone...

I wanted to drop by here to thank everyone for their thoughts and input, and to let everyone know, just for the record, how my quest to detect message sending trouble turned out.

The TL;DR version is that I got far more than I ever expected to. My code/system can detect remote email server 400 and 500 errors immediately even though I'm unable to monitor the encrypted dialog between my hMailServer and the remote server.

The key was hMailServer's COM API. Though it took some work, I created the definition headers required to access the hMailServer COM interface from assembly language (since, we as know, x86 assembler is my own "native" programming language.) This allowed me to (a) monitor hMailServer's delivery queue in real time and (b) selectively delete any items from the queue.

The breakthrough, was the discovery that immediately upon a remote email server's rejection — for whatever reason — during hMailServer's attempt to send email to a bad address or a “full” mailbox, hMailServer places an email addressed from its “mailer-daemon” to the attempted sending account (in my case “mail-authenticate”) into the delivery queue. And that email I'm able to see immediately! — This I'm able to immediately detect and act upon a failed delivery while the user is still at my submission form.

I introduced a maximum 5-second wait after the user submits their email address to give this time to happen, if it's going to. And then some tricky, JavaScript-free, CSS that allows me to display a notice to the user during the 5 seconds we're waiting to see whether the user's email immediately bounces. In my testing this always happens within one or two seconds. The tricky CSS allows that pending wait notice to be removed either once 5 seconds have elapsed or the outbound email was rejected.

Anyone who's interested of curious may play with this at https://www.grc.com/mail.htm where it's all running.

So, again, thanks for the various pointers and suggestions!
How would that behave with a receiving server that uses 451, Greylisting (temporary errors)?
CIDR to RegEx: d-fault.nl/cidrtoregex
DNS Lookup: d-fault.nl/dnstools
DKIM Generator: d-fault.nl/dkimgenerator
DNSBL Lookup: d-fault.nl/dnsbllookup
GEOIP Lookup: d-fault.nl/geoiplookup

User avatar
Steve Gibson
New user
New user
Posts: 6
Joined: 2024-05-31 04:38
Contact:

Re: Detecting failure after first delivery attempt

Post by Steve Gibson » 2024-06-23 05:24

You're 100% correct that greylisting presents a problem... Mostly because the email confirmation loop is expected to operate in real time and greylisting is deliberately non-real time.

The way I handle that is to explain to the user that if they are using a greylisting system, they'll simply need to try again after however long their system requires between the initial and the follow-up email submissions.

User avatar
SorenR
Senior user
Senior user
Posts: 6364
Joined: 2006-08-21 15:38
Location: Denmark

Re: Detecting failure after first delivery attempt

Post by SorenR » 2024-06-23 12:56

Steve Gibson wrote:
2024-06-23 05:24
You're 100% correct that greylisting presents a problem... Mostly because the email confirmation loop is expected to operate in real time and greylisting is deliberately non-real time.

The way I handle that is to explain to the user that if they are using a greylisting system, they'll simply need to try again after however long their system requires between the initial and the follow-up email submissions.
Almost everybody is using cloud based email, both private and corporate - Microsoft and Google being the primary ones.

Cloud based email killed Greylisting simply by switching to a different SMTP server every time a delivery fails... I know, I had to make a custom GreyList Whitelist script to exclude - amongst others - Outlook (Microsoft) and Gmail (Google). In the end I switched GreyListing OFF. Forum has a broken search function but the script Function is called "Sub GreyWhiteList()" and had a few posts about it around 2017/2018.

Leaving GreyListing ON automatically elevates Postmaster to BOFH as emails from e.g. Outlook Servers only gets delivered once in a blue moon ;-)

I would suggest that if delivery fails due to GreyListing you remove the recipient from your email list! Perhaps add a notice to the recipient account details for when the account logs on to re-activate delivery.
SørenR.

Woke is Marxism advancing through Maoist cultural revolution.

Post Reply