Skip to content

Instantly share code, notes, and snippets.

@CatStarwind
Forked from cflove/mail.cfm
Last active February 23, 2021 05:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save CatStarwind/2d2f85f44ec621aa1c89 to your computer and use it in GitHub Desktop.
Save CatStarwind/2d2f85f44ec621aa1c89 to your computer and use it in GitHub Desktop.
<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)#">
<cfparam name="attributes.disposition" default="attachment">
<cfset ArrayAppend(attributes.attachment,'Content-Type: #attributes.type#; name="#this.info.name#";')>
<cfset ArrayAppend(attributes.attachment,'Content-Disposition: #attributes.disposition#; 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>
@CatStarwind
Copy link
Author

Fixed bug that was causing all cf_mailparams to be attached inline regardless of disposition attribute.

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