Aug
12

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

There was a recent thread on CF-Talk about bounce management for email newsletters and thought I should write a How-to on how I have done bounce management in the past. One of the things that I will start out with is that this takes a method that I feel is much cleaner but requires you to have access to a mailserver and be able to create domains on that mailserver.

First off I am going to explain how I created my mailer and some pieces and practices I used in creating it. One thing that I started out with was creating a subdomain called nl.simplesiteonline.com. This subdomain was specifically for my newsletter bounces and I could have called it bounces.simplesiteonline.com just as well.

From there I created a postoffice on our mail server to handle email for nl.simplesiteonline.com and then created a catch-all for the domain that we will just call bounces@nl.simplesiteonline.com. A catch-all is an email address that will accept email for anything@yourdomain.com that isn't specified as a mailbox. Typically this is a no no in the spam world but this box will be fairly cleaned and the domain name never used for anything other then bounce management you should be ok.

One thing about bounce emails is that every email server seems to be different in what the message is that comes back. In that email it may or may not contain the email address of the person you are trying to reach and parsing it can be a b... well you know. This is never an exact science but I found a method that can make it just that.

Since odds are that every time you subscribe someone to your newsletter you are inserting them in the database. This means that you probably have a numeric ID to represent that email address in your database. Because of this it would be really nice to know in that bounce message what that numeric ID is.... well you can!

Here is the way it is done... When you send out an email use the CFMAIL attribute from and make it something like from="newsletter@mydomain.com" and then use the failto attributes to be "bounce--#IDOfUser#@nl.simplesiteonline.com"

This creates an email that will show the from as newsletter@ but then tell the mailserver to send a bounce to "bounce--1234@nl.simplesiteonline.com"

BAM! You now have a bounce message being sent to a unique email address that the catch-all is doing to accept.

From there the fun part starts. You will need to create a page that will process your bounces@nl.simplesiteonline.com and you can set this to be a scheduled task. Let's take a look at some code...

First off we are going to go grab the email from the POP box:

CFM:
  1. <cfpop maxrows="500" server="mail.yourserver.com" username="bounces@nl.simplesiteonline.com" password="XXXXXXXXX" action="getAll" name="GetEmail">

You will notice that I make the max row 500 since really the max you can process in a given time is about 500 at a time.

Next you want to loop over the query that CFPOP creates and then do something with each message.

CFM:
  1. <!--- Parse the message if the subject contains the right wording --->
  2. <cfloop query="GetEmail">

This right here is what makes this a bounce manager. I have found that the subject line WILL contain one of these 90% of the time. If you find that you need more just add them as you figure it out.

CFM:
  1. <cfif
  2. GetEmail.Subject CONTAINS "Undelivered" or
  3. GetEmail.Subject CONTAINS "User unknown" or
  4. GetEmail.Subject CONTAINS "Returned Mail" or
  5. GetEmail.Subject CONTAINS "failure" or
  6. GetEmail.Subject CONTAINS "failed"
  7. >
  8. <cftry>

This little piece of code runs a parser that will take "bounce--1234@nl.simplesiteonline.com" and extract the 1234 which is our user's ID

CFM:
  1. <!--- Run the parser --->
  2. <cfset supIDtoRemove = ListGetAt(ListGetAt(getEmail.to,1,"@"),2,"--")>

Next is to unsubscribe the person from your list... their email failed, we don't need them anymore! Of course this query will depend on how you are unsubscribing them, in this case we are doing a hard delete.

CFM:
  1. <!--- Run query to unsubscribe person --->
  2. <cftry>
  3. <!--- Try to delete the person --->
  4. <cfquery name="RemoveEmail" datasource="#request.dsn#">
  5. DELETE from Subscribers
  6. WHERE SubID = (<cfqueryparam value="#supIDtoRemove#" cfsqltype="cf_sql_integer">)
  7. </cfquery>
  8.  
  9. <cfcatch>
  10. </cfcatch>
  11. </cftry>

This adds the UID of the email to a list so we can delete the email if it was successfully processed

CFM:
  1. <!--- Add the UUID to the list to delete --->
  2. <cfset idsToRemove = listAppend(idsToRemove, getEmail.uid)>
  3.  
  4. <cfcatch>
  5. </cfcatch>
  6. </cftry>

I am going to delete any delayed message, out of office reply or anything automated reply

CFM:
  1. <!--- Delete the delayed messages that are annoying --->
  2. <cfelseif
  3. GetEmail.Subject CONTAINS "Delay" or
  4. GetEmail.Subject CONTAINS "Delayed" or
  5. GetEmail.Subject CONTAINS "Mail Delivery Problem" or
  6. GetEmail.Subject CONTAINS "Auto-Reply" or
  7. GetEmail.Subject CONTAINS "automated" or
  8. GetEmail.Subject CONTAINS "office"
  9. >
  10. <cfset idsToRemove = listAppend(idsToRemove, getEmail.uid)>

Now here is a fun one. We decided that if for some reason something gets in this box that neither has a failure notice or is an auto-reply we are going to forward it on to another email box. This is nice because it allows you to see what is falling through your filter and add the subject to one of the above "CONTAINS".

CFM:
  1. <cfelse>
  2.  
  3. <cfmail from="#getemail.from#" to="aLiveMailbox@yourdomain.com" subject="#getemail.subject#">
  4. #getemail.textbody#
  5. </cfmail>
  6. <!--- Just Delete messages that are not bounce messages --->
  7. <cfset idsToRemove = listAppend(idsToRemove, getEmail.uid)>
  8. </cfif>
  9. </cfloop>

After everything this is your cleanup process that deletes emails off your POP box.

CFM:
  1. <!--- Delete the messages --->
  2. <cfpop server="mail.yourdomain.com" username="bounces@nl.simplesiteonline.com" password="XXXXXXXXXXX" action="delete" uid="#idsToRemove#">

That is it. Yeah nice and simple and open for discussion!

Comments

ziggy on 25 September, 2007 at 10:04 am #

Why not use a regular email address to receive them, no subdomain, then scan the email body for the address that failed?

Also, I noticed you delete full quota emails. When I was dumping the emails and processing them somewhat manually to get a list to enter into my crude system, I always added a strike or went back to zero, then deleted if 3 strikes.


J.J. Merrick on 25 September, 2007 at 12:17 pm #

Ziggy,

The reason being is that I want to know the exact ID of the person in my system. Just scanning the email can cause undesirable results because sometimes the person being emailed may have it forwarded to an address that is defunct. The return email would list the defunct email and not the address in my system. This way I know who the person is in my system regardless of the email address that is in the body.

Later variants of this system did include a “bounce factor” and would do hard bounces and soft bounces. Soft bounces would wait until a certain threshold before deleting from the system. Hard would just do it immediately. This was determined by the subject line which usually always included “failure” in it.


Post a Comment
Name:
Email:
Website:
Comments: