Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
In this section you will find the release notes for each version we release under this major version. If you are looking for the release notes of previous major versions use the version switcher at the top left of this documentation book. Here is a breakdown of our major version releases.
Version is a major rewrite of this entire module to push it into modern land! It has been rewritten to allow for more fluent and modern syntax, more protocols, and asynchronous capabilities.
Our first release as a module decoupled from the ColdBox 2 days!
Fix usage of invalid named member function #33 (https://github.com/coldbox-modules/cbmailservices/pull/33)
A big thanks to @richardherbert for all the updates in this release.
FIXED var scoping of attachments variable
Updated to handle a response that is not JSON
🐛 FIX: Update GHA to avoid deprecated syntax
Added test for MAILGUN_BASEURL property
Updated to make MAILGUN_APIURL optional
Added support for Mailgun EU region by making MAILGUN_APIURL an optional property with https://api.mailgun.net/v3/ as the default.
Updated all GHA actions to the latest versions and moved to use temurin Java distributions due to deprecation of the service.
cbMailServices is a module to send email in a fluent and abstracted approach.
Sending emails doesn't have to be complicated or archaic. The ColdBox Mail Services (cbmailservices) module will allow you to send emails in a fluent and abstract way in multiple protocols for many environments in a single cohesive API. The supported protocols are:
CFMail - Traditional cfmail sending
File - Write emails to disk
InMemory - Store email mementos in an array. Perfect for testing.
Null - Ignores emails sent to it.
Postmark - Send via the PostMark API Service ()
Mailgun - Send via the MailGun API Service ()
It also sports tons of useful features for mail sending:
Async Mail
Mail Queues
Mail merging of variables
Mail attachments, headers, and parameters
Lucee 5+
Adobe ColdFusion 2018+
cbMailServices is maintained under the guidelines as much as possible. Releases will be numbered in the following format:
And constructed with the following guidelines:
Breaking backward compatibility bumps the major (and resets the minor and patch)
New additions without breaking backward compatibility bumps the minor (and resets the patch)
Bug fixes and misc changes bumps the patch
Apache 2 License:
Code:
Issues:
Community:
This module is professional open-source software backed by offering services like:
Custom Development
Professional Support & Mentoring
Training
Server Tuning
Because of His grace, this project exists. If you don't like this, then don't read it, it's not for you.
"Therefore being justified by faith, we have peace with God through our Lord Jesus Christ: By whom also we have access by faith into this grace wherein we stand, and rejoice in hope of the glory of God." Romans 5:5
View and Layout+View rendering for mail
Mail Tracking
Multiple mailers
Success and Error callbacks
Mailable@cbmailservices delegate for adding mailing traits to objects.
So Much More!
Security Hardening
Code Reviews
newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html", // Can be plain, html, or text
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.addAttachment( expandPath( "/tmp/reports/report.pdf" ) )
.setReadReceipt( "[email protected]" )
.send()
.onSuccess( function( result, mail ){
// Process the success
})
.onError( function( result, mail ){
// Process the error
});<major>.<minor>.<patch>May 17, 2022
Ability for the preMailSend event to influence the mail record thanks to @gpickin
Getters only work if there is a variables.config key in existence. Add reasonable defaults for commonly accessed mail fields
New module setting: runQueueTask which is defaulted to true. If false it will not run the mail queue task in the background
Leverage to install into your ColdBox app:
This will install the module in your application so you can it and . By default, it will register a mixin helper called newMail() and a WireBox ID: MailService@cbmailservices which you can inject into your models to send mail.
It will register a default mailer that uses the cfmail protocol. You can find all of the API Docs here:
ColdBox 7 Auto Testing
New start:fakemail command to start FakeSMTP for testing
Addded fake smtp server for testing on the harness
Skipping of parsing tokens if the mail type is template to avoid complex data in the send-grip protocol https://github.com/coldbox-modules/cbmailservices/pull/34
box install cbmailservicesFix github action
Fixed build process so it doesn't include box.bin in the final artifact.
The module allows you to either send mail asynchronously or queue it in an in-memory queue so it can be delivered by the mail services scheduler. So let's explore the asynchronous nature of cbmailservices.
You can easily send mail asynchronously via the ColdBox Async Manager using the sendAsync() method. This will return to you a ColdBox Future object, which then you can use to setup an async pipeline to p
newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html",
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.sendAsync()
.then( function( mail ){
// Async pipeline that can process the mail once it is sent.
})You can also detach the mail and let the cbmailservices Mail Queue send it for you. The module's mail scheduler runs on a one-minute interval and will send any mail found in the processing queue. All you need to do is use the queue() method and be done!
The queuemethod will return back a task ID guid, which you can use to track the task down in your logs or via the Mail Service.
The mail scheduler is on by default for convenience but is only needed when using the asynchronous mail feature. It can be turned off, if desired, by these steps:
Open config/coldbox.cfc
In the modulesSettings section, add a key for cbmailServices with the property runQueueTask set to false. See the section for more details.
Luis Majano is a Computer Engineer that has been developing and designing software systems since the year 2000. He was born in San Salvador, El Salvador in the late 70’s, during a period of economical instability and civil war. He lived in El Salvador until 1995 and then moved to Miami, Florida where he completed his Bachelors of Science in Computer Engineering at Florida International University. Luis resides in Houston, Texas with his beautiful wife Veronica, baby girl Alexia and baby boy Lucas!
He is the CEO of Ortus Solutions, a consulting firm specializing in web development, ColdFusion (CFML), Java development and all open source professional services under the ColdBox and ContentBox stack. He is the creator of ColdBox, ContentBox, WireBox, MockBox, LogBox and anything “BOX”, and contributes to many open source ColdFusion/Java projects. You can read his blog at
Luis has a passion for Jesus, tennis, golf, volleyball and anything electronic. Random Author Facts:
He played volleyball in the Salvadorean National Team at the tender age of 17
The Lord of the Rings and The Hobbit is something he reads every 5 years. (Geek!)
His first ever computer was a Texas Instrument TI-86 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)
Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!
“Trust in the LORD with all your heart, and do not lean on your own understanding.” Proverbs 3:5
The source code for this book is hosted in GitHub:
You can freely contribute to it and submit pull requests. The contents of this book are copyrighted by and cannot be altered or reproduced without the author's consent. All content is provided "As-Is" and can be freely distributed.
The majority of code examples in this book are done in cfscript.
The majority of code generation and running of examples are done via CommandBox: The ColdFusion (CFML) CLI, Package Manager, REPL -
He has of late (during old age) become a fan of organic gardening.
Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.
The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software, and resources described in it.
We highly encourage contributions to this book and our open-source software. The source code for this book can be found in our GitHub repository where you can submit pull requests.
10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - https://www.harvesting.org/. So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.
Shalom Children’s Home is one of the ministries that are dear to our hearts located in El Salvador. During the 12-year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.
Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education, and life skills training in a Christian environment. The home is supported by a child sponsorship program.
We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador who either have no families or have been abandoned. This is a good earth to seed and plant.
var mailId = newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html",
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.queue();If you want to build your own protocol you will have to do the following
Create a CFC that inherits from cbmailservices.models.AbstractProtocol
Create the init() and send() methods
Give your protocol a name in the init() via the variables.name variable.
Register it in the mailers section of the
Here are the method signatures of the two methods to implement:
That's it!
June 15 2022
Let’s investigate the new features and improvements.
Ability for the preMailSend event to influence the mail record thanks to @gpickin
runQueueTask This setting is defaulted to true.
If false it will not run the mail queue task in the background
You can now register a MailGun protocols by using its alias:
moduleSettings = {
cbmailServices : {
runQueueTask: false
}
}/**
* Constructor
*
* @properties The protocol properties to instantiate
*/
function init( struct properties = {} ){
variables.properties = arguments.properties;
variables.name = "MyProtocol";
return this;
}
/**
* Implemented by concrete protocols to send a message.
*
* The return is a struct with a minimum of the following two keys
* - `error` - A boolean flag if the message was sent or not
* - `messages` - An array of messages the protocol stored if any when sending the payload
*
* @payload The paylod object to send the message with
* @payload.doc_generic cbmailservices.models.Mail
*
* @return struct of { "error" : boolean, "messages" : [] }
*/
struct function send( required cbmailservices.models.Mail payload ){
}moduleSettings = {
cbMailservices : {
defaultProtocol : "default",
mailers : {
"default" : { class : "CFmail" },
"memory" : { class : "InMemory" },
"mailgun" = {
class = "Mailgun",
// Required properties
properties = {
ApiKey = '123',
domain = 'mg.somedomain.com'
}
}
}
}
}The module will register two interception points. PreMailSend and PostMailSend. These interception points are useful to alter the mail object before it gets sent out, and/or perform any functions after the mail gets sent out. An example interceptor would be:
Announced before the mail payload is sent to the chosen mailer protocol for sending. This is your last change to influence the payload.
Announced after the mail payload has been sent via the mailer protocol of choice.
component extends="coldbox.system.Interceptor"{
void function configure(){
}
function preMailSend( event, data, buffer, rc, prc ){
var environment = getSetting('environment');
var appName = getSetting('appName');
if(environment eq 'development'){
//change recipient if we are on development
data.mail.setTo('[email protected]');
//prefix the subject if we are on development
data.mail.setSubject('<DEV-#appName#> #data.mail.getSubject()#');
}
}
function postMailSend( event, data, buffer, rc, prc ){
if( data.result.error ){
//log mail failure here...
}
}
}mail
The mail payload object
mail
The mail payload object
result
struct
The result structure from the mailer protocol. At most it will contain an error boolean key and a messages array.
November 2021
cbMailServices has been rewritten from the ground up for the 2.x release. It was about time to add some 💕 and modernize it. Please note that this is a major upgrade and it WILL require some changes on your configuration and usage. We have documented all the changes for you to provide for a smooth transition.
The following are the changes you will need to do to upgrade to version 2.x.
It’s too old and too cumbersome to support now. So upgrade to a supported engine.
This CFC was unnecessary and dropped in favor of encapsulation in the MailService
You will have to place the configuration in the standard ColdBox approach now of moduleSettings.cbmailservices in the config/coldbox.cfc configuration file instead of the top level mailServices struct.
In the previous version you would put any payload mail default settings as a top-level key under the mailServices struct. Now you will use the defaults struct instead.
In 2.x you can define multiple mailers in an application. So the previous protocol struct is now removed. You will have to register the protocol by name in the mailers struct and add a defaultProtocol key which points to the one you define in the mailers.
If no defaultProtocol is added and no mailers then the mail services module will register a cfmail protocol for you as the default mailer.
Previous a struct containing error and errorArray would be returned from the send() method. Now, the Mail bean is returned (whether using mail.send() or mailService.send( mail )). The previously available struct can be accessed using mail.getResults(). (Be sure to see the .)
errorArrayThe return struct from the mail services has been modified. The errorArray has been renamed to messages. Which is still an array but can be used by any protocol to register an array of messages about the mailing for any status.
The mail payload config() method was renamed to configure()
message_id renamed to messageIdThe return message identifier from postmark has been renamed from message_id to messageID to be consistent with the postmark API results.
Let’s investigate now the new features and improvements.
The module now registers several new mixin helpers. You can now use newMail() in any handler, and interceptor to start a fluent mailing.
You can now register your mailer protocols by using their alias instead of the full CFC path:
CFMail
File
InMemory
Null
You can now also register ANY WireBox ID or class path as the mailer as well. This will allow you to register mailers that come from your application or any other module.
All protocols now have a name property that can be used to give a human readable name for all protocols.
The mail payload object has been completely rewritten to allow you to use it to not only construct a mail payload, but to do it in a fluent and more approachable manner. It also allows you to send the payload itself without using the mail service. It also sports a dynamic getter/setter approach for any property stored in the internal config structure. This structure is used to model all the mail settings and properties that will be used to send mail through any protocol.
The send() method will return itself so you can interact with the payload for either success or failures. You will do so using the following methods:
OnError( callback )
OnSuccess ( callback )
The following utility methods can be used for inspecting results and errors.
getResults() : struct. Empty if no results
hasErrors() : boolean. False if no results
getResultMessages() : array. Empty if no results
The configuration allows for a mailers structure where you can register extra named mailer protocols. You can then use them by name in your mail payloads and set the defaultProtocol as well by it's name.
You can also seed the mailer name in the payload using the setMailer() method to register the name of the mailer to use for the payload or use the mailer configuration key.
Allow for the payload to render a view as the body for you instead of doing this manually using the setView() method.
This will tell the mail payload to render the view with or without the layout, pass in the args into the view and layout as the body of the mailing. If you don't pass a layout by convention we will just render the view in isolation.
Thanks to ColdBox futures you can now send the mailing asynchronously via the sendAsync() method. The return is a ColdBox Future object.
The mail services module will also register a mail scheduler that will iterate and send mail payload asynchronously. The scheduler runs every minute and iterates and sends all mail in the queue. This allows for your application to not wait and block until mail is sent.
All you need to do is use the queue() method. That’s it. The mail services schedule will deliver the mail payload to the right mailer asynchronously and at least every minute schedule.
Please note that we are in async land, so you won’t be able to process successes or failures. The scheduler will log all activity to the applications logging facilities for either a success or failed mailing. The return of the queue() method is a task ID guid which you can use to track in log statements.
Postmark
moduleSettings = {
cbMailservices : {
}
};cbmailservices : {
tokenMarker : "@",
defaults : {
from : "[email protected]",
cc : "[email protected]",
server : "myserver"
}
}cbmailservices : {
defaultProtocol : "cfmail",
mailers : {
"files" : { class : "File" },
"cfmail" : { class : "CFMail" }
}
}mailService
.newMail()
.configure(
from = "[email protected]",
to = "[email protected]",
subject = "Mail With Params - Hello Luis"
)function save( event, rc, prc ){
...
newMail( to: "[email protected]", subject : "Hello" )
.setBody( "hello body" )
.send();
}moduleSettings = {
cbMailservices : {
defaultProtocol : "default",
mailers : {
"default" : { class : "CFmail" },
"memory" : { class : "InMemory" }
}
}
}moduleSettings = {
cbMailservices : {
defaultProtocol : "default",
mailers : {
"default" : { class : "CFmail" },
"amazon" : { class : "Mailer@amazonsns" }
}
}
}/**
* Initialize the InMemory protocol
*
* @properties A map of configuration properties for the protocol
*/
InMemoryProtocol function init( struct properties = {} ){
variables.name = "InMemory";
super.init( argumentCollection = arguments );
variables.mail = [];
return this;
}mailService
.newMail()
.configure(
from = "[email protected]",
to = "[email protected]",
subject = "Mail With Params - Hello Luis"
)
.setBody( "Hello This is my great unit test" )
.addMailParam(
name = "Disposition-Notification-To",
value = "[email protected]"
)
.addMailParam( name = "Importance", value = "High" )
.send()
.onSuccess ( () => {
} )
.onError( () => {
} );newMail( to: "[email protected]" )
.setSubject( "This is my email confirmation" )
.setBody( "You got in buddy!" )
.send()
.onSuccess ( () => {
} )
.onError( () = > {
} );cbMailservices : {
// Default Token marker
tokenMarker : "@",
// Default protocol
defaultProtocol : "file",
// Mailers
mailers : {
file : { class: "", properties : {} },
postmark : { class: "", properties : {} },
amazon : { class: "", properties : {} }
},
...
}// Using constructor
newMail( mailer : "amazon" )
// Using setter
newMail()
.setMailer( "amazon" )newMail()
.setView(
view : "View",
module : "view module",
layout : "layout",
layoutModule : "layout module",
args : {}
)future = newMail()
.setView( "report" )
.sendAsync()var taskId = newMail()
...
.queue();Up up and away!
You can initiate a mail payload via the mixin helper (newMail()) or via the injected mail service's newMail() method. The arguments you pass into this method will be used to seed the payload with all the arguments passed to the cfmail tag or the chosen protocol properties. You can also pass an optional mailer argument that will override the default protocol to one of your likings.
The newMail() helper is useful so you can send mail from your handlers and interceptors.
If you are using ColdBox 7 you can use the Mailable@cbMailservices delegate to add mailing capabilities to ANY model managed by WireBox. It will add the newMail() method to your objects:
Use the WireBox ID of MailService@cbmailservices to inject the service in any model object to send mail from your models.
The return of the newMail() calls will be a Mail payload object of type cbmailservices.models.Mail. You can find all the full API Docs here:
This object will be used to set properties that the mail protocols can use to send mail. We also have several utility methods that can be used to set mail headers, attachments, read receipts, send receipts and so much more. Let's start investigating the Mail Payload Object.
The newMail() or configure() method is used to initiate and configure a mail payload. Any argument you pass into these methods will be used to seed the mail config property which is used by all protocols to send email out. Example, the cfmail protocol will read all those properties and pass them as an attribute collection to the cfmail tag.
You will leverage the send() method to initiate a call to the mail protocols to deliver your mail using your payload. You can then tap into the results of the mailing via the mail or the . Please also note that the sending operation points (preMailSend, postMailSend) that you can use to influence the mail payload or listen to mail results.
The mail payload allows you to register two callbacks to determine what happened to the mail payload when sending:
onSuccess( callback )
onError( callback )
Each callback argument is a function/closure/lambda that receives two arguments:
result : The result structure with at least two keys: { error :boolean, messages: array }
mail : The mail payload itself.
You can easily change to use a specific mailer protocol by specifying the mailer argument to the newMail() calls or by calling the setMailer( mailer ) method.
The mail service allows you to register a structure of tokens that can be replaced by key name on the body content for you. The tokens are demarcated by the tokenMarker setting which defaults to @. Here is the token pattern:
Before sending the mail, the service will replace all the tokens with the specific key names in your content and then send the mail. You can use the bodyTokens argument to the newMail() or configure() methods, or you can use the setBodyTokens() method.
You can also set the body of the email to be a view or a layout+view combination using the setView() method. Here is the method signature:
Please note that you can bind your views and layotus with the args structure as well. You can also use the bodyTokens in your views. Then you can use it in your mail sending goodness:
You can easily add mail attachments using mail params (next section) directly or our fancy helper method called addAttachments().
Here is our method signature:
The files argument can be a list of file locations or an array of file locations to send.
You can easily add mail parameters (cfmailparam) to a payload so you can attach headers or files to the message by using the addMailParam() method. Please see the https://cfdocs.org/cfmailparam cfmail param docs for more information.
You can also add mail parts via the cfmailpart feature of cfmail (https://cfdocs.org/cfmailpart). This allows you to build multi-parted emails.
We have also registered several methods to help you when sending mail:
setReadReceipt( email ) - Set the read receipt email
setSendReceipt( email ) - Set the send receipt email
setHtml( body ) - Set a multi-part body for html
The Mail object has some additional methods to allow you to pass additional information so protocols can leverage them:
setText( body ) - Set a multi-part body for text
addAttachments( files, remove=false) - Easily add attachments
getMemento() - Get the entire mail settings for the payload
hasErrors():boolean - Verifies if there are any errors in the mailing
getResultMessages():array - Get's the array of messages of the sending of the mail
getResults():struct - Get the structure of the results of sending the mail
// Mixin Helper Approach
newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html", // Can be plain, html, or text
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.send()
.onSuccess( function( result, mail ){
// Process the success
})
.onError( function( result, mail ){
// Process the error
});component name="UserService" delegates="Mailable@cbMailservices"{
...
newMail()
.send();
}component{
property name="mailService" inject="MailService@cbmailservices";
...
function submitOrder( required order ){
...
variables.mailService
.newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html",
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.send()
.onSuccess( function( result, mail ){
// Process the success
})
.onError( function( result, mail ){
// Process the error
});
}
}variables.mailService
.newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html",
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
newMail()
.configure(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html",
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
).send()
.onSuccess( function( result, mail ){
// Process the success
})
.onError( function( result, mail ){
// Process the error
});newMail( mailer : "files" ),,,
newMail()
.setMailer( "files" )@tokenName@// Via constructor
newMail(
to : "[email protected]",
from : "[email protected]",
subject : "Mail Services Rock",
type : "html",
bodyTokens : {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
}
)
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.send()
// Body Tokens Method
newMail(
to : "[email protected]",
subject : "Mail Services Rock",
type : "html",
)
.setBodyTokens( {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
})
.setBody("
<p>Dear @user@,</p>
<p>Thank you for downloading @product@, have a great day!</p>
<p><a href='@link@'>@link@</a></p>
")
.send()/**
* Render or a view layout combination as the body for this email. If you use this, the `type`
* of the email will be set to `html` as well. You can also bind the view/layout with
* the args struct and use them accordingly. You can also use body tokens that the service will
* replace for you at runtime.
*
* @view The view to render as the body
* @args The structure of arguments to bind the view/layout with
* @module Optional, the module the view is located in
* @layout Optional, If passed, we will render the view in this layout
* @layoutModule Optional, If passed, the module the layout is in
*/
Mail function setView(
required view,
struct args = {},
module = "",
layout,
layoutModule = ""
)newMail(
to : "[email protected]",
subject : "Mail Services Rock",
type : "html",
)
.setBodyTokens( {
user : "Luis",
product : "ColdBox",
link : event.buildLink( 'home' )
})
.setView( view : "emails/newUser" )
.send()
newMail(
to : "[email protected]",
subject : "Mail Services Rock",
type : "html",
)
.setView( view : "emails/newUser", layout : "emails" )
.send()/**
* Add attachment(s) to this payload using a list or array of file locations
*
* @files A list or array of files to attach to this payload
* @remove If true, ColdFusion removes attachment files (if any) after the mail is successfully delivered.
*/
Mail function addAttachments( required files, boolean remove = false )newMail(
subject = "Hello",
from = "[email protected]",
to = "[email protected]",
body = "Here are your docs"
)
.addAttachments( "c:\temp\reports\report.pdf", true )
.addAttachments( expandpath( "/reports/anotherReport.pdf" ), true )
.addAttachments( [
expandPath( "/logs/maillog.txt" )
expandPath( "/logs/maillog2.txt" )
], true )
.send();/**
* Attach a file or adss a header to the email payload
*
* @contentID The Identifier for the attached file.
* @disposition How the attached file is to be handled: attachment, inline
* @file Attaches file to a message. Mutually exclusive with name argument.
* @type The MIME media type for the attachment.
* @name The name of the email header to attach. See https://cfdocs.org/cfmailparam. Mututally exclusive with file
* @value The value of the header
* @remove Tells ColdFusion to remove any attachments after sucdcesful mail delivery
* @content Lets you send the contents of a ColdFusion variable as an attachment
*/
Mail function addMailParam(
contentID,
disposition,
file,
type,
name,
value,
boolean remove,
content
)newMail()
.configure(
from = "[email protected]",
to = "[email protected]",
subject = "Mail With Params - Hello Luis"
)
.setBody( "Hello This is my great unit test" )
.addMailParam(
name = "Disposition-Notification-To",
value = "[email protected]"
)
.addMailParam( name = "Importance", value = "High" )
.send();/**
* Add a new mail part to this mail payload
*
* @charset The charset of the part, defaults to utf-8
* @type The valid mime type: text/plain or text/html
* @wraptext Specifies the maximum line length, in characters of the mail text.
* @type The MIME media type for the attachment.
* @body The body of the email according to the type.
*/
Mail function addMailPart(
charset = "utf-8",
type,
numeric wraptext,
body
){newMail(
from = "[email protected]",
to = "[email protected]",
subject = "Mail MultiPart No Params - Hello Luis"
)
.addMailPart(
type = "text",
body = "You are reading this message as plain text, because your mail reader does not handle it."
)
.addMailPart( type = "html", body = "<h1>This is the body of the message.</h1>" )
.send()mail.setAdditionalInfo( struct );
mail.getAdditionalInfo();
mail.setAdditionalInfoItem( key, value );
mail.getAdditionalInfoItem( key );

Let's get up and running!
You can configure the module by creating a cbmailservices key under the moduleSettings structure in the config/Coldbox.cfc file or the new ColdBox 7 approach of creating a config/modules/cbmailservices.cfc
Here, you will configure all the different mailers, default protocol, default sending settings, and more.
By default, the mail services are configured to send mail via the cfmail tag using a mailer called default.
The tokenMarker is used when doing mail merges with variables. The service will look in the body of the email and do replacements according to the following pattern:
The name of the mailer key will be used by default to send mail. The default is called default.
A structure of mailer protocol registrations by key name. Each mailer is registered with the following pattern:
A structure of default variables will be seeded into the Mail payload. The protocols then use these as defaults. For example, the CFMail protocol will use all these as defaults to the cfmail tag.
By default, a task runs every minute to facilitate sending emails asynchronously (non-blocking). Setting runQueueTask to false will override the default, and the task will not run.
The mail services can send mail via different protocols. The available protocol aliases you can register are:
CFMail
Null
InMemory
Please note that some of the protocols have property requirements.
You can also register ANY WireBox ID or classpath as the mailer. This will allow you to register mailers from your application or any other module.
FileMailgun
Postmark
moduleSettings = {
cbmailServices = {
// The default token Marker Symbol
tokenMarker : "@",
// Default protocol to use, it must be defined in the mailers configuration
defaultProtocol : "default",
// Here you can register one or many mailers by name
mailers : {
"default" : { class : "CFMail" },
"files" : { class:"File", properties : { filePath : "/logs" } },
"postmark" : { class:"PostMark", properties : { apiKey : "234" } },
"mailgun" : { class:"Mailgun", properties : {
apiKey : "234",
domain: 'mailgun.example.com'
} }
},
// The defaults for all mail config payloads and protocols
defaults : {
from : "[email protected]",
cc : "[email protected]"
},
//Whether the scheduled task is running or not
runQueueTask : true
}
}@{key}@mailerKey : {
class : "Alias|wireBoxID|CFCPath",
properties : {}
}defaultProtocol : "default",
mailers : {
// Default CFMail
"default" : {
class : "CFMail"
},
// FileProtocol
"files" = {
class = "File",
// Required Properties
properties = {
filePath = "logs",
autoExpand = true
}
},
// NullProtocol
"null" = {
class = "Null",
properties = {}
},
// InMemoryProtocol
"memory" = {
class = "InMemory",
properties = {}
},
// PostMark
"postmark" = {
class = "Postmark",
// Required properties
properties = {
apiKey = "123"
}
},
// MailGun
"mailgun" = {
class = "Mailgun",
// Required properties
properties = {
apiKey = "123",
domain = "mailgun.example.com",
// Optional property, defaults to https://api.mailgun.net/v3/
// https://documentation.mailgun.com/en/latest/api-intro.html#base-url-1
// https://documentation.mailgun.com/en/latest/api-intro.html#mailgun-regions-1
baseURL = "https://api.eu.mailgun.net/v3/" // for the EU region
}
};
}moduleSettings = {
cbMailservices : {
defaultProtocol : "default",
mailers : {
"default" : { class : "CFmail" },
// Custom amazon mailer from the amazonsns module
"amazon" : { class : "Mailer@amazonsns" }
}
}
}