Skip to content

πŸ“§ Service to assist with sending emails from Vapor apps

Notifications You must be signed in to change notification settings

vapor-community/mailgun

Folders and files

NameName
Last commit message
Last commit date

Latest commit

66cde42 Β· May 12, 2024
May 10, 2024
Jan 13, 2020
Jan 13, 2020
Jul 16, 2020
Jul 16, 2020

Repository files navigation

Mailgun

Discord Platforms Swift 5.2 Vapor 4

Mailgun is a Vapor 4 service for a popular email sending API

Note: Vapor3 version is available in vapor3 branch and from 3.0.0 tag

Installation

Mailgun can be installed with Swift Package Manager

.package(url: "https://github.com/vapor-community/mailgun.git", from: "5.0.0")

.target(name: "App", dependencies: [
    .product(name: "Vapor", package: "vapor"),
    .product(name: "Mailgun", package: "mailgun")
])

Usage

Sign up and set up a Mailgun account here

Make sure you get an API key and register a custom domain

Configure

In configure.swift:

import Mailgun

// Called before your application initializes.
func configure(_ app: Application) throws {
    /// case 1
    /// put into your environment variables the following keys:
    /// MAILGUN_API_KEY=...
    app.mailgun.configuration = .environment

    /// case 2
    /// manually
    app.mailgun.configuration = .init(apiKey: "<api key>")
}

Note: If your private api key begins with key-, be sure to include it

Declare all your domains

extension MailgunDomain {
    static var myApp1: MailgunDomain { .init("mg.myapp1.com", .us) }
    static var myApp2: MailgunDomain { .init("mg.myapp2.com", .eu) }
    static var myApp3: MailgunDomain { .init("mg.myapp3.com", .us) }
    static var myApp4: MailgunDomain { .init("mg.myapp4.com", .eu) }
}

Set default domain in configure.swift

app.mailgun.defaultDomain = .myApp1

Usage

Mailgun is available on both Application and Request

// call it without arguments to use default domain
app.mailgun().send(...)
req.mailgun().send(...)

// or call it with domain
app.mailgun(.myApp1).send(...)
req.mailgun(.myApp1).send(...)

In configure.swift

import Mailgun

// Called before your application initializes.
func configure(_ app: Application) throws {
    /// configure mailgun

    /// then you're ready to use it
    app.mailgun(.myApp1).send(...).whenSuccess { response in
        print("just sent: \(response)")
    }
}

πŸ’‘ NOTE: All the examples below will be with Request, but you could do the same with Application as in example above.

In routes.swift:

Without attachments
import Mailgun

func routes(_ app: Application) throws {
    app.post("mail") { req -> EventLoopFuture<ClientResponse> in
        let message = MailgunMessage(
            from: "[email protected]",
            to: "[email protected]",
            subject: "Newsletter",
            text: "This is a newsletter",
            html: "<h1>This is a newsletter</h1>"
        )
        return req.mailgun().send(message)
    }
}
With attachments
import Mailgun

func routes(_ app: Application) throws {
    app.post("mail") { req -> EventLoopFuture<ClientResponse> in
        let fm = FileManager.default
        guard let attachmentData = fm.contents(atPath: "/tmp/test.pdf") else {
          throw Abort(.internalServerError)
        }
        let bytes: [UInt8] = Array(attachmentData)
        var bytesBuffer = ByteBufferAllocator().buffer(capacity: bytes.count)
        bytesBuffer.writeBytes(bytes)
        let attachment = File.init(data: bytesBuffer, filename: "test.pdf")
        let message = MailgunMessage(
            from: "[email protected]",
            to: "[email protected]",
            subject: "Newsletter",
            text: "This is a newsletter",
            html: "<h1>This is a newsletter</h1>",
            attachments: [attachment]
        )
        return req.mailgun().send(message)
    }
}
With template (attachments can be used in same way)
import Mailgun

func routes(_ app: Application) throws {
    app.post("mail") { req -> EventLoopFuture<ClientResponse> in
        let message = MailgunTemplateMessage(
            from: "[email protected]",
            to: "[email protected]",
            subject: "Newsletter",
            template: "my-template",
            templateData: ["foo": "bar"]
        )
        return req.mailgun().send(message)
    }
}
Setup content through Leaf

Using Vapor Leaf, you can easily setup your HTML Content.

First setup a leaf file in Resources/Views/Emails/my-email.leaf

<html>
    <body>
        <p>Hi #(name)</p>
    </body>
</html>

With this, you can change the #(name) with a variable from your Swift code, when sending the mail

import Mailgun

func routes(_ app: Application) throws {
    app.post("mail") { req -> EventLoopFuture<ClientResponse> in
        let content = try req.view().render("Emails/my-email", [
            "name": "Bob"
        ])

        let message = Mailgun.Message(
            from: "[email protected]",
            to: "[email protected]",
            subject: "Newsletter",
            text: "",
            html: content
        )

        return req.mailgun().send(message)
    }
}
Setup routes
public func configure(_ app: Application) throws {
    // sets up a catch_all forward for the route listed
    let routeSetup = MailgunRouteSetup(forwardURL: "http://example.com/mailgun/all", description: "A route for all emails")
    app.mailgun().setup(forwarding: routeSetup).whenSuccess { response in
        print(response)
    }
}
Handle routes
import Mailgun

func routes(_ app: Application) throws {
    let mailgunGroup = app.grouped("mailgun")
    mailgunGroup.post("all") { req -> String in
        do {
            let incomingMail = try req.content.decode(MailgunIncomingMessage.self)
            print("incomingMail: (incomingMail)")
            return "Hello"
        } catch {
            throw Abort(.internalServerError, reason: "Could not decode incoming message")
        }
    }
}
Creating templates
import Mailgun

func routes(_ app: Application) throws {
    let mailgunGroup = app.grouped("mailgun")
    mailgunGroup.post("template") { req -> EventLoopFuture<ClientResponse> in
        let template = MailgunTemplate(name: "my-template", description: "api created :)", template: "<h1>Hello {{ name }}</h1>")
        return req.mailgun().createTemplate(template)
    }
}