salmon.bounce module

Bounce analysis module for Salmon. It uses an algorithm that tries to simply collect the headers that are most likely found in a bounce message, and then determine a probability based on what it finds.

class salmon.bounce.BounceAnalyzer(headers, score)[source]

Bases: object

BounceAnalyzer collects up the score and the headers and gives more meaningful interaction with them. You can keep it simple and just use is_hard, is_soft, and probable methods to see if there was a bounce. If you need more information then attributes are set for each of the following:

  • primary_status – The main status number that determines hard vs soft.

  • secondary_status – Advice status.

  • combined_status – the 2nd and 3rd number combined gives more detail.

  • remote_mta – The MTA that you sent mail to and aborted.

  • reporting_mta – The MTA that was sending the mail and has to report to you.

  • diagnostic_codes – Human readable codes usually with info from the provider.

  • action – Usually ‘failed’, and turns out to be not too useful.

  • content_parts – All the attachments found as a hash keyed by the type.

  • original – The original message, if it’s found.

  • report – All report elements, as salmon.encoding.MailBase raw messages.

  • notification – Usually the detailed reason you bounced.

Initializes all the various attributes you can use to analyze the bounce results.

error_for_humans()[source]

Constructs an error from the status codes that you can print to a user.

is_hard()[source]

Tells you if this was a hard bounce, which is determined by the message being a probably bounce with a primary_status greater than 4.

is_soft()[source]

Basically the inverse of is_hard()

probable(threshold=0.3)[source]

Determines if this is probably a bounce based on the score probability. Default threshold is 0.3 which is conservative.

class salmon.bounce.bounce_to(soft, hard)[source]

Bases: object

Used to route bounce messages to a handler for either soft or hard bounces. Set the soft/hard parameters to the function that represents the handler. The function should take one argument of the message that it needs to handle and should have a route that handles everything.

WARNING: You should only place this on the START of modules that will receive bounces, and every bounce handler should return START. The reason is that the bounce emails come from mail daemons not the actual person who bounced. You can find out who that person is using message.bounce.final_recipient. But the bounce handler is actually interacting with a message from something like MAILER-DAEMON@somehost.com. If you don’t go back to start immediately then you will mess with the state for this address, which can be bad.

salmon.bounce.detect(msg)[source]

Given a message, this will calculate a probability score based on possible bounce headers it finds and return a salmon.bounce.BounceAnalyzer object for further analysis.

The detection algorithm is very simple but still accurate. For each header it finds it adds a point to the score. It then uses the regex in BOUNCE_MATCHERS to see if the value of that header is parsable, and if it is it adds another point to the score. The final probability is based on how many headers and matchers were found out of the total possible.

Finally, a header will be included in the score if it doesn’t match in value, but it WILL NOT be included in the headers used by BounceAnalyzer to give you meanings like remote_mta and such.

Because this algorithm is very dumb, you are free to add to BOUNCE_MATCHERS in your boot files if there’s special headers you need to detect in your own code.

salmon.bounce.match_bounce_headers(msg)[source]

Goes through the headers in a potential bounce message recursively and collects all the answers for the usual bounce headers.