Tuesday, January 20, 2009

How do I send e-mail in HTML format?

How do I send e-mail in HTML format?
You should make sure that your content is easy enough to read for those that have disabled HTML, are using a web interface that doesn't allow HTML through, or are using a mail reader without HTML support (e.g. Pine). In cases where you can offer alternate content, you should tell the user that they may have to re-construct the link. In addition, the latest build of my chosen mailreader allows me to turn off HTML completely (in both preview pane and full view); I've also recently started playing with a macro that strips the HTMLbody portion of an incoming Outlook e-mail -- so I can even stop reading Comic Sans MS, which one of my co-workers insists on using. That messiness, combined with the fact that many people turn off HTML to prevent web bugs etc., leads me to encourage you to do anything you can to use the above methods *before* going the HTML route. AS more people learn of the methods to disable HTML mail, the HTML solution will work in a smaller and smaller percentage of your audience.

From ASP

Okay, enough chatter, here's some code that will help you construct HTML e-mail from a variety of mail objects available in ASP. If you know of another mail object that supports HTML format, please let us know and we'll add a code sample.

<%

' set up

CONST SMTPServer = "your.mailserver.com"
' only required for CDO.Message method:
CONST cdoURL = "http://schemas.microsoft.com/cdo/configuration/"

CONST FromAddress = "you@yourdomain.com"
CONST FromName = "Your Name"
CONST ToAddress = "them@theirdomain.com"
CONST ToName = "Their Name"
CONST Subject = "The subject of the message"
CONST url = "http://www.wherever.com/"
htmlbody = "<html><body>Please <a href='" & url & "'>register</a>.</body></html>"
textbody = "Please register:" & vbCrLf & url

' for CDO.Message:

set cdoM = CreateObject("CDO.Message")
set cdoC = CreateObject("CDO.Configuration")

Set cdoF = cdoC.Fields
With cdoF
.Item(cdoURL & "sendusing") = 2
.Item(cdoURL & "smtpserver") = SMTPServer
.Item(cdoURL & "smtpconnectiontimeout") = 10
.Update
End With

With cdoM
Set .Configuration = cdoC
.From = FromAddress
.To = ToAddress
.Subject = Subject
.HTMLBody = htmlbody

' alternate for non-HTML-aware:

.TextBody = textbody
.Send
End With

Set cdoM = Nothing
Set cdoS = Nothing
Set cdoF = Nothing

' for ASPMail / ASPQMail:

Set ASPMailer = CreateObject("SMTPsvg.Mailer")
With ASPMailer
.RemoteHost = SMTPServer
.ContentType = "text/html"
.FromName = FromName
.FromAddress = FromAddress
.AddRecipient ToName, ToAddress
.Subject = Subject
.BodyText = htmlbody
.SendMail
End With
Set ASPMailer = Nothing

' for ASPEmail:

Set ASPEMailer = CreateObject("Persits.MailSender")
With ASPEmailer
.Host = SMTPServer
.IsHTML = True
.FromName = FromName
.From = FromAddress
.AddAddress ToAddress, ToName
.Subject = Subject
.Body = htmlbody
.Send
End With
Set ASPEMailer = Nothing

If you have a registered copy of ASPEmail 4.5, you can provide multipart content, so that non-HTML-aware readers can have an alternate version:

<%
Set RegASPEMailer = CreateObject("Persits.MailSender")
With RegASPEmailer
.Host = SMTPServer
.IsHTML = True
.FromName = FromName
.From = FromAddress
.AddAddress ToAddress, ToName
.Subject = Subject
.Body = htmlbody
.AltBody = textbody
.Send
End With
Set RegASPEMailer = Nothing
%>

If you are using the OstroSoft SMTP component, you can use the following code:

<%
Set osmailer = CreateObject("OSSMTP.SMTPSession")
With osmailer
.Server = SMTPServer
.MailFrom = FromName & " <" & FromAddress & ">"
.SendTo = ToAddress
.MessageSubject = Subject
.MessageHTML = htmlbody
.MessageText = textbody
.SendEmail
End With
Set osmailer = nothing
%>

For more information on sending HTML mail with CDO.Message, see KB #286430 and KB #286431. For information about sending HTML mail with CDONTS.NewMail, see KB #189945. Keep in mind that CDONTS does not allow you to configure an alternative message for plain text viewers, so this would not be the optimal choice. If you're on Windows 2000 or greater, you should already be migrating your code to CDO.Message anyway, since CDONTS is deprecated (and doesn't even ship in Windows XP and Windows Server 2003).

From SQL Server

If you've actually managed to configure SQL Mail, and are successfully using XP_SendMail, you'll quickly find that it doesn't support sending formats other than plain text. Microsoft claims this is a limitation of MAPI, but I seem to recall that Outlook uses MAPI, and it has no problems sending HTML mail. For more details, see Question #10 from KB #311231, as well as KB #268440.

If you are using XP_SMTP_SendMail, you can use the @type parameter to specify text/html format.

EXEC master.dbo.xp_smtp_sendmail
@server = 'smtp.yourdomain.com',
@from = 'you@yourdomain.com',
@to = 'them@theirdomain.com',
@subject = 'HTML Testing...',
@type = 'text/html',
@body = '<a href=#>foo</a>'

For more information about sending mail from SQL Server, see Article #2403.

Embedding images in the e-mail

This question comes up often enough that I decided to create an addendum for this article.

Before I show the code, I will suggest once again (as I always do in the conversation) that forcing users to store and cache your HTML and graphics on their machine is rather presumptuous. So I hope you are using this method for an *opt-in* mailing where users *actively* chose HTML format and understand that your content will live on their machine.

I will also provide the disclaimer that many people set their mail clients to display mail in plain text only, so this technique will be lost on those people. It also uses a Microsoft-proprietary MHTML format, and I have not tested what happens in clients other than Outlook and Outlook Express.

Okay, the basic principle is that you create an HTML page that looks exactly like your e-mail. If you need variables inserted (e.g. you are sending personalized content via CDO in a loop), make it an ASP page that accepts parameters to fill in the content in the returned HTML. Then you just point CDO at the URL, and it takes care of gathering the HTML and formatting the message with embedded images.

<%
SMTPServer = "your.mail.server"
cdoURL = "http://schemas.microsoft.com/cdo/configuration/"

FromAddress = "you@yourdomain.com"
FromName = "Your Name"
ToAddress = "them@theirdomain.com"
ToName = "Their Name"
Subject = "The subject of the message"

textbody = "We sent you an HTML page, but you will have " & _
"http://www.wherever.com/ to see it."

MHTMLBody = "http://www.wherever.com/"

Set cdoM = CreateObject("CDO.Message")
Set cdoC = CreateObject("CDO.Configuration")
Set cdoF = cdoC.Fields

With cdoF
.Item(cdoURL & "sendusing") = 2
.Item(cdoURL & "smtpserver") = SMTPServer
.Item(cdoURL & "smtpconnectiontimeout") = 10
.Update
End With

With cdoM
Set .Configuration = cdoC

' here is the key!

.CreateMHTMLBody MHTMLBody
.From = FromAddress
.To = ToAddress
.Subject = Subject
.TextBody = textbody
.Send
End With

Set cdoM = Nothing
Set cdoS = Nothing
Set cdoF = Nothing
%>

Yes, I'll probably get burned at the stake for this one. But I think I put enough disclaimers up top that I can just point at this article instead of chastising people who are going to abuse the technology.
Related Articles
Can I get CDO messages to return a read receipt?
Can I use a remote SMTP server with CDONTS.NewMail?
How do I alter the priority / importance of an e-mail message?
How do I prevent my links from wrapping in an e-mail?
How do I put carriage returns into an e-mail?
How do I send e-mail from ASP?
How do I send e-mail from SQL Server?
How do I send e-mail with CDO?
How do I validate an e-mail address?
Should I use form action=mailto: to mail the results of a form?
Where can I get more details about configuring / using CDO?
Why can't ASP handle 80,000 e-mails?
Why do CDONTS messages end up in the badmail folder?
Why do I get 8000900F errors?
Why do I get 80040108 errors?
Why do I get 8004020A errors?
Why do I get 80090020 errors?
Why do I get C00402CE / C00402C7 errors?
Why does CDO.Message give 800C000D errors?
Why does CDO.Message give me 8004020F errors?
Why does CDO.Message give me 80040213 errors?
Why does CDO.Message give me 80040222 errors?
Why does my CDONTS mail hang out in the queue or pickup folders?
Why is e-mail to certain domains being rejected?

No comments: