Skip to content

A library that allows you to quickly and easily send emails through SendGrid using Swift.

License

Notifications You must be signed in to change notification settings

nevinjethmalani/sendgrid-swift

 
 

Repository files navigation

SendGrid-Swift

This library allows you to quickly and easily send emails through SendGrid using Swift.

Important: Breaking Changes

Version 0.1.0 and higher have been migrated over to use SendGrid's V3 Mail Send Endpoint, which contains code-breaking changes.

Full Documentation

Full documentation of the library is available here.

Table Of Contents

Installation

With Cocoapods

Add the following to your Podfile:

pod 'SendGrid', :git => 'https://github.com/scottkawai/sendgrid-swift.git'

As A Submodule

Add this repo as a submodule to your project and update:

cd /path/to/your/project
git submodule add https://github.com/scottkawai/sendgrid-swift.git

This will add a sendgrid-swift folder to your directory. Next, you need to add all the Swift files under /sendgrid-swift/Sources/ to your project.

Usage

Authorization

The V3 endpoint supports API keys for authorization (Note: username and passwords cannot be used for authorization). Using the Session class, you can configure an instance with your API key to be used over and over again to send email requests:

let session = Session()
session.authentication = Authentication.ApiKey("SG.abcdefghijklmnop.qrstuvwxyz012345-6789")

/*
`Session` also has a singleton instance that you can configure once and reuse throughout your code.
*/
Session.sharedInstance.authentication = Authentication.ApiKey("SG.abcdefghijklmnop.qrstuvwxyz012345-6789")

Content

To specify the content of an email, use the Content class. In general, an email will have plain text and/or HTML text content, however you can specify other types of content, such as an ICS calendar invite. Following RFC 1341, section 7.2, if either HTML or plain text content are to be sent in your email: the plain text content needs to be first, followed by the HTML content, followed by any other content.

Personalizations

The new V3 endpoint introduces the idea of "personalizations." When using the API, you define a set of global characteristics for the email, and then also define seperate personalizations, which contain recipient-specific information for the email. Since personalizations contain the recipients of the email, each request must contain at least 1 personalization.

// Send a basic example
let personalization = Personalization(recipients: "[email protected]")
let plainText = Content(contentType: ContentType.PlainText, value: "Hello World")
let htmlText = Content(contentType: ContentType.HTMLText, value: "<h1>Hello World</h1>")
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: [plainText, htmlText],
    subject: "Hello World"
)
do {
    try Session.sharedInstance.send(email)
} catch {
    print(error)
}

An Email instance can have up to 1000 Personalization instances. A Personalization can be thought of an individual email. It can contain several to addresses, along with cc and bcc addresses. Keep in mind that if you put two addresses in a single Personalization instance, each recipient will be able to see each other's email address. If you want to send to several recipients where each recipient only sees their own address, you'll want to create a seperate Personalization instance for each recipient.

The Personalization class also allows personalizing certain email attributes, including:

If a Personalization instance contains an email attribute that is also defined globally in the request (such as the subject), the Personalization instance's value takes priority.

Here is an advanced example of using personalizations:

// Send an advanced example
let recipients = [
    Address(emailAddress: "[email protected]", displayName: "Jose"),
    Address(emailAddress: "[email protected]", displayName: "Isaac"),
    Address(emailAddress: "[email protected]", displayName: "Tim")
]
let personalizations = recipients.map { (recipient) -> Personalization in
    let name = recipient.name ?? "there"
    return Personalization(
        to: [recipient],
        cc: nil,
        bcc: [Address(emailAddress: "[email protected]")],
        subject: "Hello \(name)!",
        headers: ["X-Campaign":"12345"],
        substitutions: ["%name%":name],
        customArguments: ["campaign_id":"12345"]
    )
}
let contents = Content.emailContent(
    plain: "Hello %name%,\n\nHow are you?\n\nBest,\nSender",
    html: "<p>Hello %name%,</p><p>How are you?</p><p>Best,<br>Sender</p>"
)
let email = Email(
    personalizations: personalizations,
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: nil
)
email.headers = [
    "X-Campaign": "12345"
]
email.customArguments = [
    "campaign_id": "12345"
]
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

You'll notice in the example above, the global email defines custom headers and custom arguments. In addition, each personalization defines some headers and custom arguments. For the resulting email, the headers and custom arguments will be merged together. In the event of a conflict, the personalization's values will be used.

Attachments

The Attachment class allows you to easily add attachments to an email. All you need is to convert your desired attachment into NSData and initialize it like so:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
if let path = NSBundle.mainBundle().pathForResource("proposal", ofType: "pdf"),
    pdf = NSData(contentsOfFile: path)
{
    let attachment = Attachment(
        filename: "proposal.pdf",
        content: pdf,
        disposition: .Attachment,
        type: .PDF,
        contentID: nil
    )
    email.attachments = [attachment]
}
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

You can also use attachments as inline images by setting the disposition property to .Inline and setting the cid property. You can then reference that unique CID in your HTML like so:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<img src=\"cid:main_logo_12345\" /><h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
if let path = NSBundle.mainBundle().pathForImageResource("logo.png"),
    logo = NSData(contentsOfFile: path)
{
    let attachment = Attachment(filename: "logo.png", content: logo, disposition: .Inline, type: .PNG, contentID: "main_logo_12345")
    email.attachments = [attachment]
}
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

Mail and Tracking Settings

There are various classes available that you can use to modify the mail and tracking settings for a specific email.

MAIL SETTINGS

The following mail setting classes are available:

Setting Description
BCCSetting This allows you to have a blind carbon copy automatically sent to the specified email address for every email that is sent.
BypassListManagement Allows you to bypass all unsubscribe groups and suppressions to ensure that the email is delivered to every single recipient. This should only be used in emergencies when it is absolutely necessary that every recipient receives your email. Ex: outage emails, or forgot password emails.
Footer The default footer that you would like appended to the bottom of every email.
SandboxMode This allows you to send a test email to ensure that your request body is valid and formatted correctly. For more information, please see our Classroom.
SpamChecker This allows you to test the content of your email for spam.

TRACKING SETTINGS

The following tracking setting classes are available:

Setting Description
ClickTracking Allows you to track whether a recipient clicked a link in your email.
GoogleAnalytics Allows you to enable tracking provided by Google Analytics.
OpenTracking Allows you to track whether the email was opened or not, but including a single pixel image in the body of the content. When the pixel is loaded, we can log that the email was opened.
SubscriptionTracking Allows you to insert a subscription management link at the bottom of the text and html bodies of your email. If you would like to specify the location of the link within your email, you may specify a substitution tag.

EXAMPLE

Each setting has its own properties that can be configured, but here's a basic example:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
email.mailSettings = [
    Footer(
        enable: true,
        text: "Copyright 2016 MyCompany",
        html: "<p><small>Copyright 2016 MyCompany</small></p>"
    )
]
email.trackingSettings = [
    ClickTracking(enable: true),
    OpenTracking(enable: false)
]
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

Unsubscribe Groups (ASM)

If you use SendGrid's unsubscribe groups feature, you can specify which unsubscribe group to send an email under like so:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
/// Assuming your unsubscribe group has an ID of 4815…
email.asm = ASM(groupID: 4815)
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

You can also specify which unsubscribe groups should be shown on the subscription management page for this email:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
/// Assuming your unsubscribe group has an ID of 4815…
email.asm = ASM(groupID: 4815, groupsToDisplay: [16,23,42])
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

IP Pools

If you're on a pro plan or higher, and have set up IP Pools on your account, you can specify a specific pool to send an email over like so:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
/// Assuming you have an IP pool called "transactional" on your account…
email.ipPoolName = "transactional"
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

Scheduled Sends

If you don't want the email to be sent right away, but rather at some point in the future, you can use the sendAt property. NOTE: You cannot schedule an email further than 72 hours in the future. You can also assign an optional, unique batchID to the email so that you can cancel via the API in the future if needed.

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
// Schedule the email for 24 hours from now.
email.sendAt = NSDate(timeIntervalSinceNow: 24 * 60 * 60)

// This part is optional, but by setting the batch ID, we have the ability to cancel this send via the API if needed.
email.batchID = "76A8C7A6-B435-47F5-AB13-15F06BA2E3WD"

do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

In the above example, we've set the sendAt property on the global email, which means every personalization will be scheduled for that time. You can also set the sendAt property on a Personalization if you want each one to be set to a different time, or only have certain ones scheduled:

let recipientInfo: [String:NSDate?] = [
    "[email protected]": NSDate(timeIntervalSinceNow: 4 * 60 * 60),
    "[email protected]": nil,
    "[email protected]": NSDate(timeIntervalSinceNow: 12 * 60 * 60)
]
let personalizations = recipientInfo.map { (recipient, date) -> Personalization in
    let personalization = Personalization(recipients: recipient)
    personalization.sendAt = date
    return personalization
}
let contents = Content.emailContent(
    plain: "Hello there,\n\nHow are you?\n\nBest,\nSender",
    html: "<p>Hello there,</p><p>How are you?</p><p>Best,<br>Sender</p>"
)
let email = Email(
    personalizations: personalizations,
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: nil
)
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

Categories

You can assign categories to an email which will show up in your SendGrid stats, Email Activity, and event webhook. You can not have more than 10 categories per email.

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
email.categories = ["Foo", "Bar"]
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

Sections

Sections allow you to define large blocks of content that can be inserted into your emails using substitution tags. An example of this might look like the following:

let bob = Personalization(recipients: "[email protected]")
bob.substitutions = [
    ":salutation": ":male",
    ":name": "Bob",
    ":event_details": "event2",
    ":event_date": "Feb 14"
]

let alice = Personalization(recipients: "[email protected]")
alice.substitutions = [
    ":salutation": ":female",
    ":name": "Alice",
    ":event_details": "event1",
    ":event_date": "Jan 1"
]

let casey = Personalization(recipients: "[email protected]")
casey.substitutions = [
    ":salutation": ":neutral",
    ":name": "Casey",
    ":event_details": "event1",
    ":event_date": "Aug 11"
]

let personalization = [
    bob,
    alice,
    casey
]
let plainText = ":salutation,\n\nPlease join us for the :event_details."
let htmlText = "<p>:salutation,</p><p>Please join us for the :event_details.</p>"
let content = Content.emailContent(plain: plainText, html: htmlText)
let email = Email(
    personalizations: personalization, 
    from: Address(emailAddress: "[email protected]"), 
    content: content
)
email.subject = "Hello World"
email.sections = [
    ":male": "Mr. :name",
    ":female": "Ms. :name",
    ":neutral": ":name",
    ":event1": "New User Event on :event_date",
    ":event2": "Veteran User Appreciation on :event_date"
]

Template Engine

If you use SendGrid's Template Engine, you can specify a template to apply to an email like so:

let personalization = Personalization(recipients: "[email protected]")
let contents = Content.emailContent(
    plain: "Hello World",
    html: "<h1>Hello World</h1>"
)
let email = Email(
    personalizations: [personalization],
    from: Address(emailAddress: "[email protected]"),
    content: contents,
    subject: "Hello World"
)
/// Assuming you have a template with ID "52523e14-7e47-45ed-ab32-0db344d8cf9z" on your account…
email.templateID = "52523e14-7e47-45ed-ab32-0db344d8cf9z"
do {
    try Session.sharedInstance.send(email, onComplete: { (response, error) in
        print(response?.stringValue)
    })
} catch {
    print(error)
}

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-fancy-new-feature)
  3. Commit your changes (git commit -am 'Added fancy new feature')
  4. Write tests for any changes and ensure existing tests pass
  5. Push to the branch (git push origin my-fancy-new-feature)
  6. Create a new Pull Request

License

The MIT License (MIT)

Copyright (c) 2016 Scott K.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

A library that allows you to quickly and easily send emails through SendGrid using Swift.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 96.6%
  • Ruby 3.1%
  • Objective-C 0.3%