CFMail Best-Practices for Sending Web-Generated E-mail (e-cards, forward-to-a-friend, etc.)

There are a number of ColdFusion articles available addressing CFMail being detected as spam, etc. which primarily deal with the "Message-ID" contained in an email's header. Charlie Arehart has a couple of detailed examples on his blog which I recommend other ColdFusion developers consider reading:

While we will also be dealing with email headers, this article is primarily concerned with addressing suggestions brought forth by the Sender Policy Framework (SPF) and their article titled How web-generated e-mailers can avoid looking like forgers. In addition, the vast majority of projects I'm involved with are hosted in a shared-hosting environment. So we won't be modifying anything in the CFAdmin area.

If you're wondering how to view email headers, I found a pretty good link on the University of Delaware Police Computer Forensics Lab web site (I know, sounds pretty serious, doesn't it).

The code examples I use here have been tested on ColdFusion 8.0.1. However, these should work with CF 6, 7 and 8.0.0 with very little, if any, modifications.

To send a web-generated email, you should collect at a minimum the "From" email, the "To" email, a "Message," and preferably the senders "Name." Obviously, there are several other things you could collect such as "Subject" and who to "Cc" or "Bcc," but let's just keep this simple for now. So let's create a form to send a simple message using the following code:


<div style="padding:20px; background-color:#CCCCCC; border:1px solid #000000; width:325px;">
    <cfform id="form1"
            name="form1"
            method="post"
            action="#cgi.SCRIPT_NAME#?#cgi.QUERY_STRING#">

        <p><label for="messageFromName">From Name:</label><br />
        <cfinput     type="text"
                    name="messageFromName"
                    id="messageFromName"
                    value="Suzie Visitor"
                    validate="noblanks"
                    size="30"
                    required="yes"
                    message="Name is required." />
</p>
        <p><label for="messageFromEmail">From Email:</label><br />
        <cfinput     type="text"
                    name="messageFromEmail"
                    id="messageFromEmail"
                    value="suzie.vistor@gmail.com"
                    validate="email"
                    size="30"
                    required="yes"
                    message="A valid email FROM is required." />
</p>
        <p><label for="messageTo">To:</label><br />
        <cfinput     type="text"
                    name="messageTo"
                    id="messageTo"
                    value="friend@theirdomain.com"
                    validate="email"
                    size="30"
                    required="yes"
                    message="A valid email TO is required." />
</p>
        <p><label for="messageText">Message:</label><br />
        <cfinput    type="text"
                    name="messageText"
                    id="messageText"
                    value="My simple message goes here."
                    validate="noblanks"
                    maxlength="160"
                    size="50"
                    required="yes"
                    message="Message is required." />
</p>
        <p><cfinput type="hidden" name="submitted" value="1" />
        <cfinput     type="submit"
                    name="submit"
                    value="Submit"
                    validate="submitonce" />
</p>
    </cfform>
    <!--- place cursor in the first form element --->
    <script type="text/javascript" language="JavaScript">
        document.forms['form1'].elements['messageFromName'].focus();
    </script>
</div>

Running the code should produce something similar to this:

Form Sample 1

The form doesn't do anything just yet other than post to the page/template it resides on. So let's go over the important stuff and then add some processing to the page.

According to SPF's article previously mentioned, when a web site sends web-generated e-mail, a user interacts with the web site, and an e-mail goes out on their behalf. Unfortunately, under SPF, mail from this type of service appears to be a forgery thereby being flagged as spam — unless certain precautions are taken. SPF claims that evite.com and egreetings.com have made the necessary changes and holds them up as examples other developers should emulate.

Your knee-jerk reaction to creating a CFMail to handle the form submission above might look like this:


<!---
    in a shared-hosting environment, you'll need to supply "server"
    and more than likely "username" and "password" too
--->

<cfmail    to="#trim(FORM.messageTo)#"
        from="#trim(FORM.messageFromName)# <#trim(FORM.messageFromEmail)#>"
        server="mail.yourdomain.com"
        username="info@yourdomain.com"
        password="y0urP@55w0rdH3r3"
        subject="Message from: #trim(FORM.messageFromName)#"
        type="text"
        charset="utf-8">

<cfmailpart type="text/plain" charset="utf-8">
#trim(FORM.messageText)#
</cfmailpart>
</cfmail>

However, this might (probably will) appear to be spam because it would generate something like this whilst using mail.yourdomain.com to send it:

Return-Path: suzie.visitor@gmail.com
From: "Suzie Visitor" <suzie.visitor@gmail.com>
Subject: Message from Suzie Visitor

SPF claims that "messages that use the user's address, but come from your mail servers are considered suspicious by SPF. To solve this problem, just change the headers ...

Here's a recommended example from SPF:

Return-Path: info@yourdomain.com
From: "Suzie Visitor" <info@yourdomain.com>
Reply-To: "Suzie Visitor" <suzie.visitor@gmail.com>
Subject: Message from Suzie Visitor

Keys to remember:

  • Choose a general address from your domain (info@yourdomain.com)
  • Add / Change the return-path (or "failto" in the CFMail tag) to that address
  • Change the "From" header ("from" in the CFMail tag) to that same address
  • Add a "Reply-To" header (yep, you guessed it, "replyto" in the CFMail tag) that contains your user's email address

So, to summarize, you can simply add the following code directly after the form and update the appropriate fields as necessary:


<cfparam name="REQUEST.errors" default="" />

<!--- PROCESS FORM SUBMISSION --->
<cfif isDefined("FORM.submitted") and FORM.submitted EQ 1>

    <!--- create an implicit empty array to track form validation errors --->
    <!--- if using CF 6 or 7, you will have to modify the following line by
    changing the square brackets [] to ArrayNew(1) --->

    <cfset REQUEST.errors = [] />

    <!--- validate required form field entries --->
    <cfif NOT len(trim(FORM.messageFromName))>
        <cfset ArrayAppend(REQUEST.errors, "Name is required.") />
    </cfif>
    <cfif NOT isValid("email", trim(FORM.messageFromEmail))>
        <cfset ArrayAppend(REQUEST.errors, "A valid email FROM is required.") />
    </cfif>
    <cfif NOT isValid("email", trim(FORM.messageTo))>
        <cfset ArrayAppend(REQUEST.errors, "A valid email TO is required.") />
    </cfif>
    <cfif NOT len(trim(FORM.messageText))>
        <cfset ArrayAppend(REQUEST.errors, "Message is required.") />
    </cfif>

    <!--- as long as there are NO errors, then process the contents --->
    <cfif NOT ArrayLen(REQUEST.errors)>

    <cftry>
        <!--- send the email --->
        <cfmail    to="#trim(FORM.messageTo)#"
                from="#trim(FORM.messageFromName)# <info@yourdomain.com>"
                failto="info@yourdomain.com"
                username="info@yourdomain.com"
                password="y0urP@55w0rdH3r3"
                replyto="#trim(FORM.messageFromName)# <#trim(FORM.messageFromEmail)#>"
                server="mail.yourdomain.com"
                subject="Message from: #trim(FORM.messageFromName)#"
                type="text"
                charset="utf-8">

        <cfmailpart type="text/plain" charset="utf-8">
        #trim(FORM.messageText)#
        </cfmailpart>
        </cfmail>
        <cfcatch>
            <cfoutput>#cfcatch.Message#</cfoutput>
        </cfcatch>
    </cftry>

    <!--- show friendly message to submitter --->
    <cfoutput>
        <p>Your message has been sent at <em>#dateformat(now(), "long")# #timeformat(now(), "long")#</em> as follows:</p>
        <p>TO: #FORM.messageTo#<br />
        SUBJECT: Message from: #FORM.messageFromName#<br />
        MESSAGE:<br /></p>
        #htmleditformat(FORM.messageText)#        
    </cfoutput>
    
    <cfelse>
        <!--- if required form values weren't given, show message to submitter --->
        <cfoutput>
            <h4>Please review the following issues:</h4>
            <ul>
                <cfloop index="intError" from="1" to="#ArrayLen(REQUEST.errors)#" step="1">
                    <li>#REQUEST.errors[intError]#</li>
                </cfloop>
            </ul>        
        </cfoutput>
    
    </cfif>

</cfif>

By following this example, you should be able to create some pretty interesting web-generated email applications that fit within the Sender Policy Framework guidelines.

If you have additional information, please feel free to share it! I hope this helps you in your next project.

Comments
Many thanks. Useful post. I found a number of other interesting posts on your blog - much appreciated.
# Posted By Johan | 7/25/08 6:25 PM
Hey Stephen. Using the example from your article (stripped for brevity):
from="#trim(FORM.messageFromName)# <info@yourdomain.com>"
...
server="mail.yourdomain.com"

We're using one email server for many different domains, so it would look more like:

from="#trim(FORM.messageFromName)# <info@theirdomain.com>"
...
server="mail.ourdomain.com"

Where 'theirdomain' is the domain where the clients web form is located and 'ourdomain' refers to the general smtp server we send all emails from. This doesn't seem correct in how we've set this up. Or will this work? Is there a way around this? Thanks.
# Posted By Mailman | 10/21/08 3:55 PM
@Mailman,

Your current method could be flagged as potential spam because the from address does not match the actual sending domain (or server).

Actually, I've run into this myself on a past project and this is what we did:

failto:"info@actualMailServer.com"
server="mail.actualMailServer.com"
from="Client Name <info@actualMailServer.com>"
replyto="#trim(FORM.messageFromName)# <#trim(FORM.messageFromEmail)#>"


Be sure to include the "failto" because this represents the Return-Path in SPF. So, just some minor changes to your setup and you should be within the SPF recommendations.

Hope this helps!
# Posted By Stephen Withington | 10/21/08 8:51 PM
Stephen, this was one of my favorite posts of 2008. I remember I used to be an online assignment writer back then and this was the only post I liked. I got a lot of inspiration from this post and that was why I became a writer myself.
# Posted By online assignment writer | 4/14/18 11:59 AM
The Practicing are done to sending non-sense emails to the friends and now waiting for the response and reply if any friend will become online to checking emails. Generated emails on the friend ID by https://www.parenttoolkit.com/academics/news/gener... website they only can reply if create the modified code.
# Posted By Xavier Burwell | 9/29/18 2:28 AM
Very informative post! There is a lot of information here that can help any business get started with a successful social networking campaign.
# Posted By jasa pembuatan aplikasi android  | 10/4/18 7:18 AM
Cool stuff you have got and you keep update all of us.
# Posted By Long Island wine tour limo  | 10/5/18 6:57 AM
I am incapable of reading articles online very often, but I’m happy I did today. It is very well written, and your points are well-expressed. I request you warmly, please, don’t ever stop writing.
# Posted By affordable wordpress website design | 10/6/18 12:11 AM
Thanks for a wonderful share. Your article has proved your hard work and experience you have got in this field. Brilliant .i love it reading.
# Posted By business blogs that accept guest posts | 10/7/18 5:35 AM
Pretty good post. I have just stumbled upon your blog and enjoyed reading your blog posts very much.
# Posted By http://www.schluesseldienstberlin.de/ | 10/9/18 9:44 PM
De jour ou de nuit, 24 24, 365 jours par ans, vous pouvez appeler afin d'obtenir une aide précieuse et juste pour votre avenir. Retrouvez confiance en la vie, faites confiance à la voyance.

# Posted By voyance gratuite par telephone | 10/11/18 5:36 AM
Succeed! It could be one of the most useful blogs we have ever come across on the subject. Excellent info! I’m also an expert in this topic so I can understand your effort very well. Thanks for the huge help.
# Posted By SCR888 | 10/12/18 9:41 PM
Best work you have done, this online website is cool with great facts and looks. I have stopped at this blog after viewing the excellent content. I will be back for more qualitative work.
# Posted By igienizare aer conditionat | 10/13/18 12:24 AM
Hey, this day is too much good for me, since this time I am reading this enormous informative article here at my home. Thanks a lot for massive hard work.
# Posted By ABCya | 10/13/18 1:11 PM
Thanks for the blog loaded with so many information. Stopping by your blog helped me to get what I was looking for.
# Posted By http://www.herbalplug.com/ | 10/14/18 10:06 PM
I have a hard time describing my thoughts on content, but I really felt I should here. Your article is really great. I like the way you wrote this information.
# Posted By Friv | 10/15/18 9:48 PM
You're the best to share us about this redesign. Trust you won't get tired on making posts as useful as this
Thanks for the information. I follow your news daily. We would love to hear more from you, just keep posting. Cheers.
<a href="https://autoketing.com/project/sales-pop-master&qu...; pop on sales </a>
<a href="https://apps.shopify.com/sales-pop-master">...; sale notification app</a>
<a href="https://autoketing.com/">; apps autoketing </a>
# Posted By Linh CP | 10/16/18 6:48 AM
Keep up the good work , I read few posts on this web site and I conceive that your blog is very interesting and has sets of fantastic information.
# Posted By http://www.tuk-design.de/ | 10/19/18 12:11 AM
A very excellent blog post. I am thankful for your blog post. I have found a lot of approaches after visiting your post.
# Posted By ABCya3 | 10/20/18 10:28 PM
Awesome and interesting article. Great things you've always shared with us. Thanks. Just continue composing this kind of post.
<a href="https://autoketing.com/">; autoketing.com</a>
<a href="https://apps.shopify.com/shipping-bar-master?utm_s...; App Shipping Bar Master </a>
<a href="https://autoketing.com/project/shipping-bar-master...; Shipping Bar for Shopify </a>
# Posted By Linh CP | 10/22/18 5:26 AM
A very excellent blog post. I am thankful for your blog post. I have found a lot of approaches after visiting your post.
# Posted By pet urns | 10/22/18 6:18 AM
Your work is very good and I appreciate you and hopping for some more informative posts. Thank you for sharing great information to us.
# Posted By http://www.dhhz.de/ | 10/27/18 10:30 PM
I feel good when reading your posts. Those are what I want to know. Thank you for introducing useful information to us
<a href="https://autoketing.com/">; https://autoketing.com</a>;
<a href="https://autoketing.com/project/discount-master?utm... master by autoketing </a>
<a href="https://apps.shopify.com/discount-master?utm_sourc...; Discount master app</a>
# Posted By Linh CP | 10/29/18 8:25 AM
This is such a great resource that you are providing and you give it away for free. I love seeing blog that understand the value of providing a quality resource for free.
# Posted By Branding | 10/30/18 1:58 AM
Hi there! Nice stuff, do keep me posted when you post again something like this!
# Posted By Search Resumes | 10/31/18 2:12 AM
If you are looking for more information about flat rate locksmith Las Vegas check that right away.
# Posted By Play Gangstar Vegas on Android | 11/1/18 1:49 AM
Keep up the good work , I read few posts on this web site and I conceive that your blog is very interesting and has sets of fantastic information.
# Posted By new york top rated security | 11/2/18 1:13 AM
I read that Post and got it fine and informative.
# Posted By Blogs  | 11/3/18 1:09 AM
how to sew in hair cheap human hair lace front wigs with baby hair https://www.hair-extensions2go.co.uk loose hair extensions she by shilo hair extensions https://www.moptopz.co.uk best gmail extensions 2018 lightweight hair dryer https://www.cheaphairforextensions.co.uk mobile hairdresser central london kinky twists hair https://www.extensionofbeauty.co.uk
# Posted By sv | 11/4/18 8:49 PM
Nice to be visiting your blog once more, it has been months for me. Well this article that ive been waited for therefore long. i want this article to finish my assignment within the faculty, and it has same topic together with your article. Thanks, nice share.
# Posted By link sbobet | 11/4/18 9:13 PM
<a href="https://apps.shopify.com/currency-converter-master...; currency converter box</a>
<a href="https://autoketing.com/project/currency-converter-...; currency converter free</a>
<a href="https://autoketing.com/">; autoketing</a>
Very good points you wrote here..Great stuff...I think you've made some truly interesting points.Keep up the good work.
# Posted By Linh CP | 11/4/18 11:16 PM
I think this is an informative post and it is very beneficial and knowledgeable. Therefore, I would like to thank you for the endeavors that you have made in writing this article. All the content is absolutely well-researched. Thanks...
# Posted By goldfish life span | 11/7/18 12:09 AM
Cool stuff you have got and you keep update all of us.

# Posted By nha cai uy tin 2019 | 11/7/18 11:02 PM
I was reading your article and wondered if you had considered creating an ebook on this subject. Your writing would sell it fast. You have a lot of writing talent.
# Posted By com facebook orca | 11/8/18 5:04 AM
i really like this article please keep it up.
# Posted By Investimenti sicuri 2019 | 11/13/18 4:45 AM
Nice blog and absolutely outstanding. You can do something much better but i still say this perfect.Keep trying for the best.
# Posted By true fake id | 11/13/18 6:51 AM
Searching for BEST SUSHI NYC check out Sushi Sushi, for SUSHI NYC, SUSHI MANHATTAN, SUSHI HARLEM DELIVERY, SUSHI PRODUCTS, GREAT SUSHI NYC, SUSHI WEST VILLAGE NYC, BEST SUSHI IN WEST VILLAGE, THE BEST SUSHI, MANGO AVOCADO ROLL.
# Posted By MANGO AVOCADO ROLL | 11/15/18 5:22 AM
Nice post. I was checking constantly this blog and I am impressed! Extremely helpful information specially the last part I care for such info a lot.
# Posted By Happy new Year | 11/16/18 8:08 AM
Hi there! Nice material, do keep me posted when you post something like this again!
# Posted By clique aqui | 11/18/18 12:47 AM
i really like this article please keep it up.§§§
# Posted By ????? ???? 01 | 11/21/18 10:57 AM
I read that Post and got it fine and informative.
# Posted By Stay up to date with latest information | 11/29/18 12:25 AM
I read that Post and got it fine and informative.
# Posted By Stay up to date with latest information | 11/29/18 12:25 AM
I had to go show it to my friend and he ejoyed it as well! bulging disc
# Posted By Stay up to date with latest information | 11/30/18 11:14 PM
I had to go show it to my friend and he ejoyed it as well! bulging disc
# Posted By Stay up to date with latest information | 11/30/18 11:14 PM
thanks for this usefull article, waiting for this article like this again.
# Posted By Stay up to date with latest information | 12/30/18 9:45 PM
I'm glad I found this web site, I couldn't find any knowledge on this matter prior to.Also operate a site and if you are ever interested in doing some visitor writing for me if possible feel free to let me know, im always look for people to check out my web site.
# Posted By Stay up to date with latest information | 1/7/19 9:44 PM

© 2019, Stephen J. Withington, Jr.  |  BlogCFC was created by Raymond Camden – Version 5.9.004

Creative Commons License  |  This work is licensed under a Creative Commons Attribution 3.0 Unported License.  |  Hosted by Hostek.com