Instantly share code, notes, and snippets.

@cflove /mail.cfm
Last active May 22, 2018

Embed
What would you like to do?
ColdFusion custom mail tag to use Amazon SES API SendRawEmail call. This is will create Multipart email message and pass into SES API. Mailparam tag can be use to attach file and create custom x-headers slimier to cfmailparam tag.
<cfparam name="attributes.type" default="html">
<cfswitch expression="#thisTag.ExecutionMode#">
<cfcase value="start">
</cfcase>
<cfdefaultcase>
<!--- *************************************************** --->
<!--- Basic Errors --->
<!--- *************************************************** --->
<cfif not StructKeyExists(attributes,'from')>
<cfthrow message="From attribute is required">
</cfif>
<cfif not StructKeyExists(attributes,'to')>
<cfthrow message="TO attribute is required">
</cfif>
<cfif not StructKeyExists(attributes,'Key')>
<cfthrow message="Key attribute is required." detail="Please provide AWS Access Key ID">
</cfif>
<cfif not StructKeyExists(attributes,'SecretKey')>
<cfthrow message="SecretKey attribute is required." detail="Please provide AWS Secret Access Key">
</cfif>
<cfset attributes.boundary = "_#CreateUUID()#_">
<cfset attributes.mail = ArrayNew(1)>
<!--- *************************************************** --->
<!--- Create Header Values --->
<!--- *************************************************** --->
<cfset this.header = ArrayNew(1)>
<cfset ArrayAppend(this.header,"From: #trim(attributes.from)#")>
<cfset ArrayAppend(this.header,"To: #trim(ListChangeDelims(attributes.to,',',',;'))#")>
<cfset attributes.deliverto = attributes.to>
<cfif StructKeyExists(attributes,'cc')>
<cfset ArrayAppend(this.header,"CC: #trim(ListChangeDelims(attributes.cc,',',',;'))#")>
<cfset attributes.deliverto = ListAppend(attributes.deliverto,attributes.cc)>
</cfif>
<cfif StructKeyExists(attributes,'bcc')>
<cfset ArrayAppend(this.header,"BCC: #trim(ListChangeDelims(attributes.bcc,',',',;'))#")>
<cfset attributes.deliverto = ListAppend(attributes.deliverto,attributes.bcc)>
</cfif>
<cfif StructKeyExists(attributes,'replyto')>
<cfset ArrayAppend(this.header,"Reply-To: #trim(attributes.replyto)#")>
</cfif>
<cfif StructKeyExists(attributes,'priority') and val(attributes.priority)>
<cfset ArrayAppend(this.header,"Priority: #attributes.priority#")>
</cfif>
<!--- *************************************************** --->
<!--- Add Custom Header Values --->
<!--- *************************************************** --->
<cfif IsDefined('thisTag.AssocAttribs')>
<cfloop from="1" to="#ArrayLen(thisTag.AssocAttribs)#" index="i">
<cfset this.attr = thisTag.AssocAttribs[i]>
<cfif StructKeyExists(this.attr,'name')>
<cfparam name="this.attr.value" default="">
<cfset ArrayAppend(this.header,"#this.attr.name#: #trim(this.attr.value)#")>
</cfif>
</cfloop>
</cfif>
<cfset ArrayAppend(this.header,"Subject: #trim(attributes.subject)#")>
<cfset ArrayAppend(this.header,"MIME-Version: 1.0")>
<cfset ArrayAppend(this.header,"Content-Type: multipart/mixed; boundary=#attributes.boundary#")>
<cfset ArrayAppend(attributes.mail, ArrayToList(this.header,chr(10)) )>
<cfset ArrayAppend(attributes.mail, '#chr(10)#Your email client does not support MultiPart messages.#chr(10)#' )>
<cfset StructDelete(this,'header')>
<cfswitch expression="#attributes.type#">
<cfcase value="html">
<cfset attributes.type = "text/html">
</cfcase>
<cfdefaultcase>
<cfset attributes.type = "text/plain">
</cfdefaultcase>
</cfswitch>
<!--- *************************************************** --->
<!--- add text content --->
<!--- *************************************************** --->
<cfif len(trim(thisTag.GeneratedContent))>
<cfset ArrayAppend(attributes.mail,'--#attributes.boundary#' )>
<cfset ArrayAppend(attributes.mail,'Content-Type: #attributes.type##chr(10)#')>
<cfset ArrayAppend(attributes.mail,trim(thisTag.GeneratedContent))>
</cfif>
<!--- *************************************************** --->
<!--- add attachments --->
<!--- *************************************************** --->
<cfif IsDefined('thisTag.AssocAttribs')>
<cfloop from="1" to="#ArrayLen(thisTag.AssocAttribs)#" index="i">
<cfset this.attr = thisTag.AssocAttribs[i]>
<cfif StructKeyExists(this.attr,'attachment')>
<cfset ArrayAppend(attributes.mail,'--#attributes.boundary#' )>
<cfset ArrayAppend(attributes.mail, ArrayToList(this.attr.attachment,chr(10)) )>
</cfif>
</cfloop>
</cfif>
<cfset ArrayAppend(attributes.mail,'#chr(10)#--#attributes.boundary#--' )>
<!--- *************************************************** --->
<!--- Remove duplicate email address --->
<!--- *************************************************** --->
<cfset this.deliverto = StructNew()>
<cfloop list="#attributes.deliverto#" index="i" delimiters=",;">
<cfset this.deliverto[trim(i)] = ''>
</cfloop>
<cfset attributes.deliverto = StructKeyList(this.deliverto)>
<!--- *************************************************** --->
<!--- Calling AWS --->
<!--- *************************************************** --->
<cfset this.date = DateAdd('s',GetTimeZoneInfo().UTCTotalOffset,now()) />
<cfset this.date = "#DateFormat(this.date, 'ddd, dd mmm yyyy')# #timeFormat(this.date,'HH:mm:ss')# GMT" />
<cfset this.Signature = toBase64(HMAC_SHA256(this.date,attributes.SecretKey)) />
<cfset this.Authoriz = "AWS3-HTTPS AWSAccessKeyId=#attributes.Key#, Algorithm=HmacSHA256, Signature=#this.Signature#" />
<cfhttp url="https://email.us-east-1.amazonaws.com/" method="post" result="result">
<cfhttpparam type="header" name="X-Amzn-Authorization" value="#this.Authoriz#" />
<cfhttpparam type="header" name="Date" value="#this.date#" />
<cfhttpparam type="formfield" name="Action" value="SendRawEmail" />
<cfset count = 1>
<cfloop list="#attributes.deliverto#" index="i">
<cfhttpparam type="formfield" name="Destinations.members.#count#" value="#i#" />
<cfset count = 1+count>
</cfloop>
<cfhttpparam type="formfield" name="Source" value="#trim(attributes.from)#" />
<cfhttpparam type="formfield" name="RawMessage.Data" value="#ToBase64(trim(ArrayToList(attributes.mail,chr(10))))#" />
</cfhttp>
<cfset this.MessageId = "">
<cfif StructKeyExists(result,'Filecontent') and IsXML(result.Filecontent)>
<cfif listfirst(result.Statuscode,' ') eq '200'>
<cfset this.MessageId = XMLParse(result.Filecontent).SendRawEmailResponse.SendRawEmailResult.MessageId.XmlText>
<cfelse>
<cfset this.MessageId = 'ERROR: '& XMLParse(result.Filecontent).ErrorResponse.Error.Message.XmlText>
</cfif>
</cfif>
<cfset caller.MessageId = trim(this.MessageId)>
<!---- ************************************************************ --->
<!---- Helpers --->
<!---- ************************************************************ --->
<cffunction name="HMAC_SHA256" returntype="binary" access="public" output="no">
<cfargument name="signMessage" type="string" required="true" />
<cfargument name="signKey" type="string" required="true" />
<cfset local.jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1") />
<cfset local.jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1") />
<cfset local.key = createObject("java","javax.crypto.spec.SecretKeySpec") />
<cfset local.mac = createObject("java","javax.crypto.Mac") />
<cfset local.key = local.key.init(local.jKey,"HmacSHA256") />
<cfset local.mac = local.mac.getInstance(local.key.getAlgorithm()) />
<cfset local.mac.init(local.key) />
<cfset local.mac.update(local.jMsg) />
<cfreturn local.mac.doFinal() />
</cffunction>
<cfset thisTag.GeneratedContent = "" />
</cfdefaultcase>
</cfswitch>
<cfparam name="attributes.disposition" default="attachment">
<cfswitch expression="#thisTag.ExecutionMode#">
<cfcase value="start">
<cfassociate basetag="cf_mail">
<cfif StructKeyExists(attributes,'file')>
<!--- *************************************************** --->
<!--- File Attachment --->
<!--- *************************************************** --->
<cfif FileExists(attributes.file)>
<cfset attributes.attachment = ArrayNew(1)>
<cfset this.info = GetFileInfo(attributes.file)>
<cfparam name="attributes.type" default="#getPageContext().getServletContext().getMimeType(attributes.file)#">
<cfset ArrayAppend(attributes.attachment,'Content-Type: #attributes.type#; name="#this.info.name#";')>
<cfset ArrayAppend(attributes.attachment,'Content-Disposition: inline; filename="#this.info.name#"; size=#this.info.size#;')>
<cfif StructKeyExists(attributes,'contentID')>
<cfset ArrayAppend(attributes.attachment,"Content-ID: <#attributes.contentID#>")>
</cfif>
<cfset ArrayAppend(attributes.attachment,"Content-Transfer-Encoding: base64#chr(10)#")>
<cfset ArrayAppend(attributes.attachment,ToBase64( FileReadBinary(attributes.file) ))>
</cfif>
</cfif>
</cfcase>
<cfdefaultcase>
</cfdefaultcase>
</cfswitch>
@WaltRiceJr

This comment has been minimized.

Show comment
Hide comment
@WaltRiceJr

WaltRiceJr Aug 13, 2014

I forked this and added some preliminary support for cfmailpart and alternative html and plain text content.

WaltRiceJr commented Aug 13, 2014

I forked this and added some preliminary support for cfmailpart and alternative html and plain text content.

@CatStarwind

This comment has been minimized.

Show comment
Hide comment
@CatStarwind

CatStarwind Dec 4, 2014

I also forked this to fix a bug that made all cf_mailparam send as disposition: inline.

CatStarwind commented Dec 4, 2014

I also forked this to fix a bug that made all cf_mailparam send as disposition: inline.

@SubhanRazaKhan

This comment has been minimized.

Show comment
Hide comment
@SubhanRazaKhan

SubhanRazaKhan May 22, 2018

When i am trying to send an email i am getting error "Email address is not verified". I want to send email to my customer but without verification is it possible?

SubhanRazaKhan commented May 22, 2018

When i am trying to send an email i am getting error "Email address is not verified". I want to send email to my customer but without verification is it possible?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment