How to get the 'failed' or 'success' status of an email send node?

Hello
when using the Send eMail node, we can see under the node some dynamic information wich indicates if the mail has been sent, or not.

How can we get this information inside node-Red to know if the mail has been correctly sent?
how to test it with an other node? wich one?

Use the status node

This is a problem that I also have had. You can use a Catch node to catch errors, and a Status node to indicate the current status, and with some rather complex logic involving those you can tell when a message has been sent. This flow uses node-red-contrib-semaphore and node-red-contrib-dsm to achieve this. Pass it a message to send and it passes on an ok or fail message.
Don't be confused by the fact that the email node has an output. I generated a forked email node that passed on an ok or fail message but decided that would not be a good plan in the long term so instead developed this flow.

[{"id":"66930673.2e5878","type":"e-mail","z":"edc4c8b4.6073c8","server":"****","port":"465","secure":true,"name":"","dname":"","x":669.6363525390625,"y":139,"wires":[[]]},{"id":"1ea27bd.a480804","type":"catch","z":"edc4c8b4.6073c8","name":"email catch","scope":["66930673.2e5878"],"x":81,"y":222.99996948242188,"wires":[["4cbd58d8.c0eb78","523a7eb5.1a3be8"]]},{"id":"5e61e619.75e6f8","type":"status","z":"edc4c8b4.6073c8","name":"email status","scope":["66930673.2e5878"],"x":81,"y":271.9999694824219,"wires":[["4cbd58d8.c0eb78","523a7eb5.1a3be8"]]},{"id":"be1502b3.ca3f3","type":"change","z":"edc4c8b4.6073c8","name":"Message","rules":[{"t":"set","p":"trigger","pt":"msg","to":"message","tot":"str"},{"t":"delete","p":"error","pt":"msg"},{"t":"delete","p":"state","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":435.5,"y":64,"wires":[["4cbd58d8.c0eb78"]]},{"id":"4cbd58d8.c0eb78","type":"dsm","z":"edc4c8b4.6073c8","name":"email dsm","sm_config":"{\n    \"triggerInput\": \"trigger\",\n    \"stateOutput\": \"state\",\n    \"currentState\": \"waiting\",\n    \"msg_saved\":  \"null\",\n    \"states\": {\n        \"waiting\": {\n            \"message\": \"initiating\"\n        },\n        \"initiating\": {\n            \"status_sending\": \"sending\",\n            \"catch_error\": \"waiting_status_error\"\n        },\n        \"sending\": {\n            \"status_blank\": \"waiting\",\n            \"status_error\": \"waiting_catch_error\",\n            \"catch_error\": \"waiting_status_error\"\n        },\n        \"waiting_status_error\": {\n            \"status_error\": \"waiting\"\n        },\n        \"waiting_catch_error\": {\n            \"catch_error\": \"waiting\"\n        }\n    },\n    \"methods\": {\n        \"onBeforeTransition\": [\n            \"if (msg.error && msg.trigger != 'catch_error' ||\",\n             \" msg.status && !msg.trigger) {\",\n             \"    msg.trigger = 'evaluate';\",\n            \"}\"\n        ],\n        \"evaluate\": [\n            \"if(msg.error)\",\n            \"  resume('catch_error', msg);\",\n            \"else if (msg.status) switch (msg.status.text) {\",\n            \"  case 'email.status.sending': \",\n            \"    resume('status_sending', msg);\",\n            \"    break;\",\n            \"  case '': \",\n            \"    resume('status_blank', msg);\",\n            \"    break;\",\n            \"  case 'email.status.sendfail': \",\n            \"    resume('status_error', msg);\",\n            \"    break;\",\n            \"}\",\n            \"else node.warn('Email DSM unknown transition' + msg);\",\n            \"output = false;\"\n        ],\n        \"message\": [\n            \"sm.msg_saved = RED.util.cloneMessage(msg);\",\n            \"delete sm.msg_saved.state\",\n            \"/*node.warn('msg saved');*/\"\n        ],\n        \"status_sending\": [\n            \"output = false;\"\n        ],\n        \"status_error\": [\n            \"if (sm.currentState=='waiting') {\",\n              \"node.send(sm.msg_saved);\",\n              \"output=false;\",\n            \"} else {\",\n            \"  output = false;\",\n            \"}\"\n        ],\n        \"status_blank\": [\n            \"node.send(sm.msg_saved);\",\n            \"output=false;\"\n        ],\n        \"catch_error\": [\n            \"sm.msg_saved.error = msg.error;\",\n            \"if (sm.currentState=='waiting') {\",\n              \"node.send(sm.msg_saved);\",\n              \"output=false;\",\n            \"} else {\",\n            \"  /*node.warn('in else');*/\",\n            \"  output = false;\",\n            \"}\"\n        ]\n    },\n    \"status\": {\n        \"fill\": {\n            \"get\": \"sm.fill;\"\n        },\n        \"shape\": \"dot\",\n        \"text\": {\n            \"get\": \"sm.currentState;\"\n        }\n    }\n\n}","x":156,"y":147,"wires":[["d5afb8a3.e487a8"]]},{"id":"d5afb8a3.e487a8","type":"switch","z":"edc4c8b4.6073c8","name":"","property":"state","propertyType":"msg","rules":[{"t":"eq","v":"initiating","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":309,"y":146,"wires":[["ed8de431.acd82","51a7ec39.b3ef74"],["87df6152.bd9038"]]},{"id":"ed8de431.acd82","type":"debug","z":"edc4c8b4.6073c8","name":"","active":false,"tosidebar":true,"console":false,"complete":"true","x":646.5,"y":98,"wires":[]},{"id":"6545adc7.8c9234","type":"debug","z":"edc4c8b4.6073c8","name":"","active":false,"console":"false","complete":"true","x":644.5,"y":201,"wires":[]},{"id":"92b215ce.d679e8","type":"semaphore-take","z":"edc4c8b4.6073c8","config":"622cfa8b.806e94","name":"Acquire semaphore","x":237.5,"y":64,"wires":[["be1502b3.ca3f3"]]},{"id":"87df6152.bd9038","type":"semaphore-leave","z":"edc4c8b4.6073c8","config":"622cfa8b.806e94","name":"Release semaphore","x":613.5,"y":238,"wires":[["6545adc7.8c9234","11a52864.256a88"]]},{"id":"523a7eb5.1a3be8","type":"debug","z":"edc4c8b4.6073c8","name":"","active":false,"console":"false","complete":"true","x":316,"y":251,"wires":[]},{"id":"51a7ec39.b3ef74","type":"delay","z":"edc4c8b4.6073c8","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"10","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":515.5,"y":139,"wires":[["66930673.2e5878"]]},{"id":"a90884e9.474e58","type":"link in","z":"edc4c8b4.6073c8","name":"email in","links":["a5f9e982.58bcc"],"x":204.5,"y":23,"wires":[["92b215ce.d679e8"]]},{"id":"11a52864.256a88","type":"link out","z":"edc4c8b4.6073c8","name":"email out","links":["ac303b90.f40988"],"x":601.5,"y":290,"wires":[]},{"id":"622cfa8b.806e94","type":"semaphore-config","z":"","name":"email semaphore","capacity":"1"}]

Hi colin.
thanks for the answer.
Can you explain what dsm and semaphore contribs are used for?
I am sorry, but I am very new in node-red, and it would be great if I could understand the way your flow works.

The dsm is a digital state machine and no I can't easily explain it in detail without spending some time looking at it again, sorry. Basically it keeps track of what state the system is in (waiting for a message, sending, waiting for success or fail, etc). That is the problem with state machines they are difficult to document. The semaphore nodes prevent the next message from being passed in before the first one has either been sent or failed. Once a message passes through the Acquire Semaphore node then it will not let another through until the Release Semaphore node is triggered. Without those it is not possible to link the status and catch results to a particular message as multiple messages can be flying round the system at once.

The whole flow receives messages in the same form the email node expects them so you should be able to test it easily. Get it working with just the email node first. Then if you replace the email node with that whole flow and look at the resulting message it should be fairly obvious what is going on. If I remember correctly the message passed on is the original message with possibly msg.error added. If msg.error is present then it failed and the error message should be in there. If msg.error is not present then it succeeded in sending it.

The problem with that (and that the catch node) is that you cannot directly link the success or fail to a particular message, so if you send multiple messages you cannot easily tell which ones succeeded and which ones failed. The only way I found to do that was to do something like the flow I posted.

To be sure that only one mail is sent, until I get a success or a fail, I also extracted the information 'sending'. So, if the mail node is already sending a mail, I don't send a new one until I get a good or bad reply.
It seems that is working fine, without installing dsm nor semaphore.

If you send two in quick succession into your flow what stops the second one being sent to the email node before you get the 'sending' back from the status node?

In fact, my application is located on a PLC. The link beetween my PLC and node-Red is made via OPC-UA. OPC-UA and Node-red are on the same device.
Node-Red scans the OPC-UA variables each 10 seconds.
In my PLC, I request to send a mail by a bit : xSend.
when this bit is set by the PLC, it is maintained until I get a good or bad reply from the mail node (xFail or xSent).
So, as i scan the variables only each 10 seconds, I can not send an other mail while one is already 'on the run'.
My flow is here :slight_smile:

[{"id":"2d053491.5339ec","type":"tab","label":"Send Mail with status","disabled":false,"info":""},{"id":"82f5b33.72aac5","type":"OPCUA-IIoT-Inject","z":"2d053491.5339ec","injectType":"read","payload":"","payloadType":"date","topic":"","repeat":"5","crontab":"","once":true,"startDelay":"","name":"Scan xSend ...","addressSpaceItems":[{"name":"xSend","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSend","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.strText","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSent","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.strMailTo","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.strMailCC","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.strMailBCC","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xFail","datatypeName":""},{"name":"","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSending","datatypeName":""}],"x":246.00001907348633,"y":248.00000286102295,"wires":[["c612c1a.190544"]]},{"id":"d540f50c.5e4cd8","type":"comment","z":"2d053491.5339ec","name":"Cyclically read OPC UA varibales to send a mail","info":"","x":282.0000190734863,"y":70.00000381469727,"wires":[]},{"id":"b0cc5adb.966868","type":"change","z":"2d053491.5339ec","name":"copy mail adresses, and strText in Mail","rules":[{"t":"set","p":"to","pt":"msg","to":"payload[3].value","tot":"msg"},{"t":"set","p":"cc","pt":"msg","to":"payload[4].value","tot":"msg"},{"t":"set","p":"bcc","pt":"msg","to":"payload[5].value","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"payload[1].value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1856.0003356933594,"y":247.00004768371582,"wires":[["b03fc5ab.b67158"]]},{"id":"b03fc5ab.b67158","type":"e-mail","z":"2d053491.5339ec","server":"smtp.gmail.com","port":"465","secure":true,"name":"","dname":"Sending mail","x":2153.00048828125,"y":248.00006294250488,"wires":[]},{"id":"c612c1a.190544","type":"OPCUA-IIoT-Read","z":"2d053491.5339ec","attributeId":"13","maxAge":1,"depth":1,"connector":"5b764178.d2fd1","name":"... In the local server","justValue":true,"showStatusActivities":true,"showErrors":true,"parseStrings":false,"historyDays":"","x":442.0000190734863,"y":247.00000286102295,"wires":[["a7931e37.f3c03"]]},{"id":"a7931e37.f3c03","type":"OPCUA-IIoT-Response","z":"2d053491.5339ec","name":"Wait for answer","compressStructure":true,"showStatusActivities":true,"showErrors":true,"activateUnsetFilter":false,"activateFilters":false,"negateFilter":false,"filters":[],"x":672.0000152587891,"y":246.00000190734863,"wires":[["30312138.565c6e","8f8ad7eb.2b70b8"]]},{"id":"30312138.565c6e","type":"switch","z":"2d053491.5339ec","name":"Test xSend = true","property":"payload[0].value","propertyType":"msg","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":881.0000190734863,"y":248.00000190734863,"wires":[["96989050.e8adc"]]},{"id":"ff0a88d1.52ed88","type":"OPCUA-IIoT-Write","z":"2d053491.5339ec","connector":"5b764178.d2fd1","name":"... to local server","justValue":true,"showStatusActivities":true,"showErrors":true,"x":1954.01997756958,"y":433.00394344329834,"wires":[["9cc3f4a8.53b1c8"]]},{"id":"9cc3f4a8.53b1c8","type":"OPCUA-IIoT-Response","z":"2d053491.5339ec","name":"Wait for answer","compressStructure":false,"showStatusActivities":false,"showErrors":false,"activateUnsetFilter":false,"activateFilters":false,"negateFilter":false,"filters":[],"x":2193.0200691223145,"y":433.00399684906006,"wires":[["22649884.3945c8"]]},{"id":"22649884.3945c8","type":"debug","z":"2d053491.5339ec","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":2380.0200958251953,"y":433.00395011901855,"wires":[]},{"id":"96989050.e8adc","type":"switch","z":"2d053491.5339ec","name":"Test xSent = false","property":"payload[2].value","propertyType":"msg","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":1095.0197639465332,"y":249.00395393371582,"wires":[["6ba9753d.d3b13c"]]},{"id":"ec03d4b2.130898","type":"OPCUA-IIoT-Node","z":"2d053491.5339ec","injectType":"write","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSent","datatype":"Boolean","value":"","name":"Send xSent = false ...","topic":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSent","showErrors":false,"x":1726.5197410583496,"y":431.00401973724365,"wires":[["ff0a88d1.52ed88"]]},{"id":"8f8ad7eb.2b70b8","type":"switch","z":"2d053491.5339ec","name":"Test xSend = false","property":"payload[0].value","propertyType":"msg","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":870.5196533203125,"y":383.0039186477661,"wires":[["b0bc252c.139928"]]},{"id":"10665e38.a17e82","type":"status","z":"2d053491.5339ec","name":"'Sending mail' status","scope":["b03fc5ab.b67158"],"x":1026.999984741211,"y":800.000020980835,"wires":[["203506a5.d556aa"]]},{"id":"203506a5.d556aa","type":"switch","z":"2d053491.5339ec","name":"Extract msg.status.text","property":"status.text","propertyType":"msg","rules":[{"t":"eq","v":"","vt":"str"},{"t":"cont","v":"fail","vt":"str"},{"t":"cont","v":"sending","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":1360,"y":800,"wires":[["9d878a9e.a3ccd8","8c00f21c.f197"],["90743ff6.b1ef5","8c00f21c.f197"],["c21f9492.370598"]],"outputLabels":["OK","NOK","SENDING"]},{"id":"9d878a9e.a3ccd8","type":"OPCUA-IIoT-Node","z":"2d053491.5339ec","injectType":"write","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSent","datatype":"Boolean","value":"true","name":"Send xSent = true ...","topic":"","showErrors":false,"x":1681.0000076293945,"y":751.0000219345093,"wires":[["ff0a88d1.52ed88"]]},{"id":"90743ff6.b1ef5","type":"OPCUA-IIoT-Node","z":"2d053491.5339ec","injectType":"write","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xFail","datatype":"Boolean","value":"true","name":"Send xFail = true ...","topic":"","showErrors":false,"x":1671.0000076293945,"y":801.0000233650208,"wires":[["ff0a88d1.52ed88"]]},{"id":"47992443.379abc","type":"OPCUA-IIoT-Node","z":"2d053491.5339ec","injectType":"write","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xFail","datatype":"Boolean","value":"","name":"Send xFail - false ...","topic":"ns=5;s=Arp.Plc.Eclr/MainInstance.xFail","showErrors":false,"x":1720,"y":480,"wires":[["ff0a88d1.52ed88"]]},{"id":"ac54e4a5.3f7758","type":"switch","z":"2d053491.5339ec","name":"Test xFail = false","property":"payload[6].value","propertyType":"msg","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":1529.3333282470703,"y":250.00005054473877,"wires":[["b0cc5adb.966868"]]},{"id":"c21f9492.370598","type":"OPCUA-IIoT-Node","z":"2d053491.5339ec","injectType":"write","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSending","datatype":"Boolean","value":"true","name":"Send xSending = true ...","topic":"","showErrors":false,"x":1687.3333435058594,"y":850.0001068115234,"wires":[["ff0a88d1.52ed88"]]},{"id":"8c00f21c.f197","type":"OPCUA-IIoT-Node","z":"2d053491.5339ec","injectType":"write","nodeId":"ns=5;s=Arp.Plc.Eclr/MainInstance.xSending","datatype":"Boolean","value":"false","name":"Send xSending = false ...","topic":"","showErrors":false,"x":1683.000015258789,"y":619.0000190734863,"wires":[["ff0a88d1.52ed88"]]},{"id":"6ba9753d.d3b13c","type":"switch","z":"2d053491.5339ec","name":"Test xSending= false","property":"payload[7].value","propertyType":"msg","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":1312.666660308838,"y":249.00004768371582,"wires":[["ac54e4a5.3f7758"]]},{"id":"b0bc252c.139928","type":"change","z":"2d053491.5339ec","name":"set x... = false","rules":[{"t":"set","p":"payload","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":1265.6666564941406,"y":424.00001525878906,"wires":[["ec03d4b2.130898","47992443.379abc"]]},{"id":"d901af3a.3519","type":"comment","z":"2d053491.5339ec","name":"Scan for the 'Sending mail' node status","info":"","x":966.8333740234375,"y":745.3333549499512,"wires":[]},{"id":"4ca7fce6.074294","type":"comment","z":"2d053491.5339ec","name":"Sending mail successfull","info":"","x":1995.6666564941406,"y":749.0000305175781,"wires":[]},{"id":"90e00fd3.23699","type":"comment","z":"2d053491.5339ec","name":"Sending mail unsuccessfull","info":"","x":1995.6666870117188,"y":797.0000247955322,"wires":[]},{"id":"71e45fa6.43733","type":"comment","z":"2d053491.5339ec","name":"Sending mail running","info":"","x":1984.6666259765625,"y":849,"wires":[]},{"id":"e3a90782.61ebe8","type":"comment","z":"2d053491.5339ec","name":"The mail will be sent if xSend = true and xSent = false and xSending = false and xFail = false","info":"","x":1376.6666259765625,"y":164,"wires":[]},{"id":"5b764178.d2fd1","type":"OPCUA-IIoT-Connector","z":"","discoveryUrl":"","endpoint":"opc.tcp://127.0.0.1:4840","keepSessionAlive":true,"loginEnabled":false,"securityPolicy":"Basic128Rsa15","securityMode":"SIGNANDENCRYPT","name":"LOCAL SERVER","showErrors":true,"individualCerts":false,"publicCertificateFile":"","privateKeyFile":"","defaultSecureTokenLifetime":"","endpointMustExist":false,"autoSelectRightEndpoint":false,"strategyMaxRetry":"","strategyInitialDelay":"","strategyMaxDelay":"","strategyRandomisationFactor":"","requestedSessionTimeout":"","connectionStartDelay":"","reconnectDelay":"","maxBadSessionRequests":"10"}]

If I understand the flow correctly the PLC is effectively providing the semaphore as it will not send you the next email until you tell it you have sent the previous one, in which case that should be ok.

anyway, thank a lot to you and dceejay for the hint about the use of the 'status' node.

Yes, actually we did add (in 0.20) the ability for status to not error if extra parameters were passed as part of the status object - I haven't tried adding this ability to external nodes like email as I need to check doing so won't break earlier releases.

That would be great, if the email status could pass on the original message when it is complete or fails.

err - well hopefully not... emails can be big !

1 Like

Ah yes, not including attachments anyway. There has to be something there to identify the individual message.

could use some of the properties maybe ? msg.to ? msg.topic ?
In case of error the catch node does get the complete msg - so hopefully this is only for success ? or other info so whole msg should net be needed ?? or am I mistaken ? (often the case)
(and the good news is it doesn't seem to break 0.19.x so this can be achieved)

My requirement was that I had some emails that I had to send, and had to know that I had at least sent them (one can never guarantee that they will actually arrive, but it is rare I think to have them successfully sent then not arrive). So I put the emails into a buffer as they are ready to send, then as they are successfully sent I remove them from the buffer. If there is a failure sending (perhaps the network is down for example) then I try again later. So the requirement is that I need to know when a message is successfully sent or if there is a failure, and be able to link success or failure back to the original message so I can remove it from the buffer (or not). You said you were worried about making the whole message available via the status due to the size of it, but provided is it not cloned is that actually an issue? If that were the case then the user can put an id somewhere in the message and use that to identify it. Ideally if there is an error the specific error can be linked back to the message but probably that is less important than being able to link back the success or failure state itself.

So if you got the entire msg back, what would you compare in order to remove it from your list ?

I have an attribute msg.id that I use to find it in the buffer.