A CFML wrapper for the SendGrid's Web API v3. It currently supports building and sending transactional emails, as well as portions of the API related to marketing emails.
This project borrows heavily from the API frameworks built by jcberquist, such as xero-cfml and aws-cfml. Because it draws on those projects, it is also licensed under the terms of the MIT license.
- Installation
- Quick Start for Sending
- Setup and Authentication
- How to build an email
sendgrid.cfc
Reference Manual- Reference Manual for
helpers.mail
- Reference Manual for
helpers.campaign
- Reference Manual for
helpers.sender
- Questions
- Contributing
This wrapper can be installed as standalone component or as a ColdBox Module. Either approach requires a simple CommandBox command:
$ box install sendgridcfc
If you can't use CommandBox, all you need to use this wrapper as a standalone component is the sendgrid.cfc
file and the helper components, located in /helpers
; add them to your application wherever you store cfcs. But you should really be using CommandBox.
This component will be installed into a directory called sendgridcfc
in whichever directory you have chosen and can then be instantiated directly like so:
sendgrid = new sendgridcfc.sendgrid( apiKey = 'xxx' );
Note that this wrapper was not designed to be placed within the shared CustomTags directory. If implemented as a CustomTag, it will conflict with the older mail()
function syntax, as discussed in this issue.
To use the wrapper as a ColdBox Module you will need to pass the configuration settings in from your config/Coldbox.cfc
. This is done within the moduleSettings
struct:
moduleSettings = {
sendgridcfc = {
apiKey = 'xxx'
}
};
You can then leverage the CFC via the injection DSL: sendgrid@sendgridcfc
; the helper components follow the same pattern:
property name="sendgrid" inject="sendgrid@sendgridcfc";
property name="mail" inject="mail@sendgridcfc";
property name="campaign" inject="campaign@sendgridcfc";
property name="sender" inject="sender@sendgridcfc";
The following is a minimal example of sending an email, using the mail
helper object.
sg = new sendgrid( apiKey = 'xxx' );
mail = new helpers.mail()
.from( 'test@example.com' )
.subject( 'Sending with SendGrid is Fun' )
.to( 'test@example.com' )
.plain( 'and easy to do anywhere, even with ColdFusion');
sg.sendMail( mail );
To get started with SendGrid, you'll need an API key. First, you'll need to create an account with SendGrid; then follow the instructions in the docs for creating an API key. The relevant section is located in your account within Settings > API Keys > Create API Key.
Once you have an API key, you can provide it to this wrapper manually when creating the component, as in the Quick Start example above, or via an environment variable named SENDGRID_API_KEY
, which will get picked up automatically. This latter approach is generally preferable, as it keeps hardcoded credentials out of your codebase.
For reasons unclear to me, if you want to use SendGrid's email validation endpoint, you're required to set up a second, separate API key. Note that the email validation service is only available to users of SendGrid's "Pro" tier or higher. If you have a "Pro" account, you can generate a dedicated Email Validation API key in the same manner as the standard API key outlined above, and as explained in their documentation.
To provide the Email Validation API key to the wrapper, you can include it manually when creating the component:
sg = new sendgrid( apiKey = 'xxx', emailValidationApiKey = 'zzz' );
Alternatively, it will automatically be picked up via an environment variable named SENDGRID_EMAIL_VALIDATION_API_KEY
. It will then be used automatically for requests to the email validation endpoint.
If you don't have a SendGrid "Pro" account and/or don't want to use SendGrid's email validation service, you can ignore this - there's no need to provide the emailValidationApiKey
for using the other methods in the wrapper.
SendGrid enables you to do a lot with their endpoint for sending emails. This functionality comes with a tradeoff: a more complicated mail object that many other transactional email providers. So, following the example of their official libraries, I've put together a mail helper to make creating and manipulating the mail object easier.
As seen in the Quick Start example, a basic helper can be created via chaining methods:
mail = new helpers.mail().from( 'name@youremail.com' ).subject( 'Hi, I love your emails' ).to( 'myfriend@email.com' ).html( '<p>Hi,</p><p>Thanks for all your emails</p>');
Alternatively, you can create the basic object with arguments, on init:
from = 'name@youremail.com';
subject = 'Hi, I love your emails';
to = 'myfriend@email.com';
content = '<p>Hi,</p><p>Thanks for all your emails</p>';
mail = new helpers.mail( from, subject, to, content );
Note that for this API wrapper, the assumption when the content
argument is passed in to init()
, is that it is HTML, and that both html and plain text should be set and sent.
The from
, subject
, to
, and message content, whether plain or html, are minimum required fields for sending an email.
I've found two places where the /mail/send
endpoint JSON body are explained, and the (77!) possible parameters outlined. Familiarizing yourself with these will be of great help when using the API: V3 Mail Send API Overview and Mail Send Endpoint Documentation.
View SendGrid Docs for Sending Mail
Sends email, using SendGrid's REST API. The mail
argument must be an instance of the helpers.mail
component. See the quick start for sending and how to build an email for more information on how this is used.
View SendGrid Docs for Blocks
Retrieve a list of all email addresses that are currently on your blocks list. The start_time
and end_time
arguments, if numeric, are assumed to be unix timestamps. Otherwise, they are presumed to be a valid date that will be converted to unix timestamps automatically.
Retrieve a specific email address from your blocks list.
View SendGrid Docs for Bounces
Retrieve a list of bounces that are currently on your bounces list. The start_time
and end_time
arguments, if numeric, are assumed to be unix timestamps. Otherwise, they are presumed to be a valid date that will be converted to unix timestamps automatically.
Retrieve specific bounce information for a given email address.
View SendGrid Docs for Campaigns
Allows you to create a marketing campaign. The campaign
argument should be an instance of the helpers.campaign
component. However, if you want to create and pass in the struct or json yourself, you can. See the campaign helper reference manual for more information on how this is used.
Retrieve a list of all of your campaigns.
Retrieve a single campaign by ID.
Delete a single campaign by ID.
Update a campaign by ID. The campaign
arguments should be an instance of the helpers.campaign
component. However, if you want to create and pass in the struct or json yourself, you can. See the campaign helper reference manual for more information on how this is used.
View SendGrid Docs for Contacts API - Recipients
Add Marketing Campaigns recipients. Note that it also appears to update existing records, so it basically functions like a PATCH. The recipients
arguments is an array of objects, with at minimum, and 'email' key/value.
addRecipient( required any recipient, string first_name = '', string last_name = '', struct customFields = {} )
Convenience method for adding a single recipient at a time. The recipient
arguments facilitates two means of adding a recipient. You can pass in a struct with key/value pairs providing all relevant recipient information. Alternatively, you can use this to simply pass in the recipient's email address, which is all that is required. The customFields
keys correspond to your custom field names, along with their assigned values.
Update one or more Marketing Campaign recipients. Note that it will also add non-existing records. The recipients
arguments is an array of objects, with at minimum, and 'email' key/value.
updateRecipient( required any recipient, string first_name = '', string last_name = '', struct customFields = {} )
Convenience method for updating a single recipient at a time. The recipient
arguments facilitates two means of adding a recipient. You can pass in a struct with key/value pairs providing all relevant recipient information. Alternatively, you can use this to simply pass in the recipient's email address, which is all that is required. The customFields
keys correspond to your custom field names, along with their assigned values.
Check the upload status of a Marketing Campaigns recipient.
Delete a single recipient with the given ID from your contact database. The id
arguments can be the recipient ID or email address (which will be converted to the recipient ID)
Deletes one or more recipients. This is an incomplete implementation of the SendGrid API. Technically, this should send a DELETE request to /contactdb/recipients
, with an array of IDs as the body. But ColdFusion doesn't currently include the request body in DELETE calls. So we loop the recipients through the individual delete method. The recipients
arguments is an array of the recipient IDs you want to delete. You can also provide their email addresses, and they will be converted to recipient IDs
Retrieve all of your Marketing Campaign recipients.
Retrieve a single recipient by ID from your contact database. The id
argument can be the recipient ID or email address (which will be converted to the recipient ID).
Retrieve the lists that a given recipient belongs to. The id
argument can be the recipient ID or email address (which will be converted to the recipient ID).
Retrieve the number of Marketing Campaigns recipients that you will be billed for.
Retrieve the total number of Marketing Campaigns recipients.
Perform a search on all of your Marketing Campaigns recipients. The fieldName
argument is the name of a custom field or reserved field. The search
argument is the value to search for within the specified field. Date fields must be unix timestamps. Currently, searches that are formatted as a U.S. date in the format mm/dd/yyyy (1-2 digit days and months, 1-4 digit years) are converted automatically.
View SendGrid Docs for Contacts API - Segments
Create a segment using search conditions.
The conditions
argument is an array of structs making up the search conditions that define this segment. Read SendGrid documentation for specifics on how to segment contacts.
The listId
argument indicates the list from which to make this segment. Not including this ID will mean your segment is created from the main contactdb rather than a list.
Retrieve all of your segments.
Retrieve a single segment with the given ID.
Update a segment. Functions similarly to createSegment()
, but you only need to include the parameters you are updating.
Note that the listId
argument can be used to change the list for this segment, but once a list has been set, the segment cannot be returned to the main contactdb.
Delete a segment from your recipients database.
Retrieve all of the recipients in a segment with the given ID.
View SendGrid Docs for Contacts API - Custom Fields
Create a custom field. For the type
arguments, the allowed values are 'text', 'date', and 'number'.
Retrieve all custom fields.
Retrieve a custom field by ID.
Delete a custom field by ID.
List all fields that are reserved and can't be used for custom field names.
View SendGrid Docs for Contacts API - Lists
Create a list for your recipients.
Retrieve all of your recipient lists. If you don't have any lists, an empty array will be returned.
Delete multiple recipient lists. This is an incomplete implementation of the SendGrid API. Technically, this should send a DELETE request to /contactdb/lists
, with an array of IDs as the body. But ColdFusion doesn't currently include the request body in DELETE calls. So we loop the lists through the individual delete method. The recipients
argument is an array of the list IDs you want to delete.
Delete a single list with the given ID from your contact database.
Retrieve a single recipient list by ID.
Update the name of one of your recipient lists.
Retrieve all recipients on the list with the given ID.
Add a single recipient to a list. The recipientId
argument can be the recipient ID or email address (which will be converted to the recipient ID).
Delete a single recipient from a list. The recipientId
argument can be the recipient ID or email address (which will be converted to the recipient ID).
Add multiple recipients to a list. The recipients
argument is an array of recipient IDs or email addresses. The first element of the array is checked to determine if it is an array of IDs or email addresses.
View SendGrid Docs for Invalid Emails
Retrieve a list of invalid emails that are currently on your invalid emails list. The start_time
and end_time
arguments, if numeric, are assumed to be unix timestamps. Otherwise, they are presumed to be a valid date that will be converted to unix timestamps automatically.
Retrieve information about a specific invalid email address.
View SendGrid Docs for Sender Identities
Allows you to create a new sender identity. The sender
argument should be an instance of the helpers.sender
component. However, if you want to create and pass in the struct or json yourself, you can. See the sender helper reference manual for more information on how this is used.
Retrieve a list of all sender identities that have been created for your account.
Update a sender identity by ID. The sender
argument should be an instance of the helpers.sender
component. However, if you want to create and pass in the struct or json yourself, you can. See the sender helper reference manual for more information on how this is used.
Delete a single sender identity by ID.
Resend a sender identity verification email.
Retrieve a single sender identity by ID.
View SendGrid Docs for Suppressions - Suppressions
Add email addresses to an unsubscribe group. If you attempt to add suppressions to a group that has been deleted or does not exist, the suppressions will be added to the global suppressions list.
Convenience method for adding a single email address to an unsubscribe group. Delegates to addEmailsToUnsubscribeGroup()
Retrieve all suppressed email addresses belonging to the given group.
Remove a suppressed email address from the given suppression group.
Retrieve a list of all suppressions.
Appears to slightly differ from the documentation. Returns all supressions groups, with an indication if the email address is supressed or not.
Search a suppression group for multiple suppressions.
Convenience method for searching for a single email within an unsubscribe group. Delegates to searchUnsubscribeGroupForEmails()
View SendGrid Docs for Suppressions - Unsubscribe Groups
Create a new unsubscribe suppression group. The name
and description
arguments are both required. They can be seen by recipients on the unsubscribe landing page. SendGrid enforces the max length of these arguments by silently trimming their values to 30 and 100 characters, respectively.
Retrieve a list of all suppression groups created by this user.
Retrieve a single suppression group.
updateUnsubscribeGroup( required numeric id, string name = '', string description = '', required boolean isDefault )
Update an unsubscribe suppression group. The name
and description
arguments can be seen by recipients on the unsubscribe landing page. SendGrid enforces the max length of these arguments by silently trimming their values to 30 and 100 characters, respectively. For updates, the isDefault
argument is required by this library, because if you don't supply it, SendGrid assumes false, which is confusing.
Delete a suppression group.
View SendGrid Docs for Cancel Scheduled Sends
Generate a new batch ID. This batch ID can be associated with scheduled sends via the mail/send endpoint.
View SendGrid Docs for Spam Reports
Retrieve a list of spam reports that are currently on your spam reports list. The start_time
and end_time
arguments, if numeric, are assumed to be unix timestamps. Otherwise, they are presumed to be a valid date that will be converted to unix timestamps automatically.
Retrieve a specific spam report by email address.
View SendGrid Docs for Validate Email
Retrive a validation information about an email address. The source param is just an one word classifier for the validation call.
Important: SendGrid's email validation endpoint requires a separate API key from their primary email API. Additionally, this service is only available on their "Pro" tier, or higher. For a bit more information about SendGrid's email validation, you can read their documentation and product page. For a little more context on how this impact this wrapper, see the note on email validation.
This section documents every public method in the helpers/mail.cfc
file. A few notes about structure, data, and usage:
- Unless indicated, all methods are chainable.
- Top level parameters are referred to as "global" or "message level", as opposed to personalized parameters. As the SendGrid docs state: "Individual fields within the personalizations array will override any other global, or βmessage levelβ, parameters that are defined outside of personalizations."
- Email address parameters can be passed in either as strings or structs.
- When passed as a string, they can be in the format: Person <name@email.com>, in order to pass both name and email address.
- When passed as a struct, the keys should be
email
andname
, respectively. Only email is required.
Sets the global subject. This may be overridden by personalizations[x].subject.
Convenience method for adding the text/html content
Convenience method for adding the text/plain content
Method for setting any content mime-type. The default is that the new mime-type is appended to the Content array, but you can override this and have it prepended. This is used internally to ensure that text/plain
precedes text/html
, in accordance with the RFC specs, as enforced by SendGrid.
Convenience method for setting both text/html
and text/plain
at the same time. You can either pass in the HTML content as the message argument, and both will be set from it (using an internal method to strip the HTML for the plain text version), or you can call the method without an argument, after having set the HTML, and that will be used.
Sets the attachments
property for the global message. If any attachments were previously set, this method overwrites them.
Appends a single attachment to the message. The attachment argument is struct with at minimum keys for content
and filename
. View the SendGrid docs for the full makeup and requirements of the object: https://sendgrid.api-docs.io/v3.0/mail-send
attachFile( required string filePath, string fileName, string type, string disposition = 'attachment', string content_id )
A convenience method for appending a single file attachment to the message. All that is required is the relative or absolute path to an on-disk file. Its properties are used if the additional arguments aren't provided.
Sets the id of a template that you would like to use for the message
Appends a single section block to the global message's sections
property. I'd recommend reading up on the somewhat limited documentation SendGrid provides about sections and substitutions for more clarity on how they should be structured and used.
You can set a section by providing the section tag and replacement value separately, or by passing in a struct with a key/value pair; for example, { "-greeting-" : 'Welcome -first_name- -last_name-,' }
.
Sets the sections
property for the global message. If any sections were previously set, this method overwrites them.
Appends a single header to the global message's headers
property. This can be overridden by a personalized header.
You can set a header by providing the header and value separately, or by passing in a struct with a key/value pair; for example, { "X-my-application-name" : 'testing' }
.
Sets the headers
property for the global message. Headers can be overridden by a personalized header. If any headers are set, this method overwrites them.
Sets the category array for the global message. If categories are already set, this overwrites them. The argument can be passed in as an array or comma separated list. Lists will be converted to arrays
Appends a single category to the global message category array
Appends a single custom argument on the global message's custom_args
property. This can be overridden by a personalized custom argument.
You can set a custom argument by providing the argument's name and value separately, or by passing in a struct with a key/value pair; for example, { "Team": "Engineering" }
.
Sets the custom_args
property for the global message. Custom arguments can be overridden by a personalized custom argument. If any custom arguments are set, this overwrites them.
Sets the global send_at
property, which specifies when you want the email delivered. This may be overridden by the personalizations[x].send_at.
Sets the global batch_id
property, which represents a group of emails that are associated with each other. The sending of emails in a batch can be cancelled or paused. Note that you must generate the batchID value via the API.
Sets the mail_settings
property for the global message. If any mail settings were previously set, this method overwrites them. While this makes it possible to pass in the fully constructed mail settings struct, the preferred method of setting mail settings is by using their dedicated methods.
Generic method for defining individual mail settings. Using the dedicated methods for defining mail settings is usually preferable to invoking this directly.
You can define a setting by providing the setting key and its value separately, or by passing in a struct with a key/value pair; for example, { "sandbox_mode" : { "enable" : true } }
.
Sets the global mail_settings.bcc
property, which allows you to have a blind carbon copy automatically sent to the specified email address for every email that is sent. Using the dedicated enable/disable bcc methods is usually preferable.
Convenience method for enabling the bcc
mail setting and setting the address
Convenience method for disabling the bcc
mail setting
Sets the global mail_settings.bypass_list_management
property, which allows you to bypass all unsubscribe groups and suppressions to ensure that the email is delivered to every single recipient. According to SendGrid, this should only be used in emergencies when it is absolutely necessary that every recipient receives your email. Using the dedicated enable/disable methods is usually preferable to invoking this directly
Convenience method for disabling the bypass_list_management
mail setting
Convenience method for disabling the bypass_list_management
mail setting
Sets the global mail_settings.footer
property, which provides the option for setting a default footer that you would like included on every email. Using the dedicated enable/disable methods is usually preferable.
Convenience method for enabling the footer
mail setting and setting the text/html
Convenience method for disabling the footer
mail setting
Sets the global mail_settings.sandbox_mode
property, which allows allows you to send a test email to ensure that your request body is valid and formatted correctly. Sandbox mode is only used to validate your request. The email will never be delivered while this feature is enabled! Using the dedicated enable/disable methods is usually preferable to invoking this directly. You can read more here.
Convenience method for disabling the sandbox_mode
mail setting
Convenience method for disabling the sandbox_mode
mail setting
Sets the global mail_settings.spam_check
property, which allows you to test the content of your email for spam. Using the dedicated enable/disable methods is usually preferable.
Convenience method for enabling the spam_check
mail setting and setting the threshold and post_to_url
Convenience method for disabling the spam_check
mail setting
Adds a new personalization envelope, with only the specified email address. The personalization can then be further customized with later commands. I found personalizations a little tricky. You can read more here.
Adds an additional 'to' recipient to the current personalization envelope
Adds an additional 'cc' recipient to the current personalization envelope. You need to add a 'to' recipient before using this.
Adds an additional 'bcc' recipient to the current personalization envelope. You need to add a 'to' recipient before using this.
Sets the subject for the current personalization envelope. This overrides the global email subject for these recipients. A basic personalization envelope (with a 'to' recipient) needs to be in place before this can be added.
Functions like header()
, except it adds the header to the current personalization envelope.
Functions like headers()
, except it sets the headers
property for the current personalization envelope. If any personalized headers are set, this method overwrites them.
Sets the dynamic_template_data
property for the current personalization envelope. If any dynamic template data had been previously set, this method overwrites it.
Note that dynamic template data is not compatible with Legacy Dynamic Templates. For more on Dynamic Templates, read the docs here.
The dynamicTemplateData
argument is an object containing key/value pairs of the dynamic template data. Basically, the Handlebars input object that provides the actual values for the dynamic template.
Appends a substitution ( "substitution_tag" : "value to substitute" ) to the current personalization envelope. You can add a substitution by providing the tag and value to substitute, or by passing in a struct.
Sets the substitutions
property for the current personalization envelope. If any substitutions are set, this method overwrites them.
Functions like customArg()
, except it adds the custom argument to the current personalization envelope.
Functions like customArgs()
, except it sets the custom_args
property for the current personalization envelope. If any personalized custom arguments are set, this method overwrites them.
Functions like sendAt()
, except it sets the desired send time for the current personalization envelope.
The function that puts it all together and builds the body for /mail/send
This section documents every public method in the helpers/campaign.cfc
file. A few notes about structure, data, and usage:
- Unless indicated, all methods are chainable.
Sets the display title of your campaign. This will be viewable by you in the Marketing Campaigns UI. This is the only required field for creating a campaign
Sets the subject of your campaign that your recipients will see.
Sets who the email is "from", using the ID of the "sender" identity that you have created.
Included in order to provide a more fluent interface; delegates to sender()
Sets the IDs of the lists you are sending this campaign to. Note that you can have both segment IDs and list IDs. If any list Ids were previously set, this method overwrites them. The lists
arguments can be passed in as an array or comma separated list. Lists will be converted to arrays.
Appends a single list Id to the array of List Ids that this campaign is being sent to.
Sets the segment IDs that you are sending this list to. Note that you can have both segment IDs and list IDs. If any segment Ids were previously set, this method overwrites them. The segments
argument can be passed in as an array or comma separated list. Lists will be converted to arrays.
Appends a single segment Id to the array of Segment Ids that this campaign is being sent to.
Set an array of categories you would like associated to this campaign. If categories are already set, this overwrites them. The categories
argument can be passed in as an array or comma separated list. Lists will be converted to arrays.
Appends a single category to campaigns array of categories.
Assigns the suppression group that this marketing email belongs to, allowing recipients to opt-out of emails of this type. Note that you cannot provide both a suppression group Id and a custom unsubscribe url. The two are mutually exclusive.
Included in order to provide a more fluent interface; delegates to suppressionGroupId()
This is the url of the custom unsubscribe page that you provide for customers to unsubscribe from mailings. Using this takes the place of having SendGrid manage your suppression groups.
Included in order to provide a more fluent interface; delegates to customUnsubscribeUrl()
The pool of IPs that you would like to send this email from. Note that your SendGrid plan must include dedicated IPs in order to use this.
Included in order to provide a more fluent interface; delegates to ipPool()
Convenience method for adding the text/html content
Redundant, but included for consistency in naming the methods for setting attributes. Delegates to html()
Convenience method for adding the text/plain content
Redundant, but included for consistency in naming the methods for setting attributes. Delegates to plain()
Convenience method for setting both html and plain at the same time. You can either pass in the HTML content, and both will be set from it (using a method to strip the HTML for the plain text version), or you can call the method without an argument, after having set the HTML, and that will be used.
The editor used in the UI. Because it defaults to code
, it really only needs to be toggled to design
The editor used in the UI. It defaults to code
, so this shouldn't be needed, but it's provided for consistency.
The function that puts it all together and builds the body for campaign related API operations.
This section documents every public method in the helpers/sender.cfc
file. A few notes about structure, data, and usage:
- Unless indicated, all methods are chainable.
- Email address parameters can be passed in either as strings or structs.
- When passed as a string, they can be in the format: Person <name@email.com>, in order to pass both name and email address.
- When passed as a struct, the keys should be
email
andname
, respectively.
Sets the nickname for the sender identity. Not used for sending, but required.
Set where the email will appear to originate from for your recipients. Note that, despite what the documentation says, both email address and name need to be provided. If a string is passed in and the name is not provided, the email address will be used as the name as well.
Set where your recipients will reply to. If a string is passed in and the name is not provided, the email address will be used as the name as well.
Required. Sets the physical address of the sender identity.
Provides additional sender identity address information.
Required.
Required.
The function that puts it all together and builds the body for sender related API operations
For questions that aren't about bugs, feel free to hit me up on the CFML Slack Channel; I'm @mjclemente. You'll likely get a much faster response than creating an issue here.
ππ First off, thanks for taking the time to contribute! ππ
Before putting the work into creating a PR, I'd appreciate it if you opened an issue. That way we can discuss the best way to implement changes/features, before work is done.
Changes should be submitted as Pull Requests on the develop
branch.