├── .gitignore ├── LICENSE ├── Other └── logo.png ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── MailCore │ ├── Extensions │ │ ├── Message+Mailgun.swift │ │ ├── Message+SMTP.swift │ │ ├── Message+SendGrid.swift │ │ └── Request+Mail.swift │ └── MailCore.swift └── MailCoreTestTools │ ├── Extensions │ └── MailProperty+Tools.swift │ └── MailCoreTestTools.swift ├── Tests └── MailCoreTests │ └── MailCoreTests.swift └── scripts ├── update.sh └── upgrade.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/vapor 3 | 4 | ### Vapor ### 5 | Config/secrets 6 | 7 | ### Vapor Patch ### 8 | Packages 9 | .build 10 | xcuserdata 11 | *.xcodeproj 12 | DerivedData/ 13 | .DS_Store 14 | 15 | # End of https://www.gitignore.io/api/vapor 16 | /.swiftpm 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 LiveUI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Other/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LiveUI/MailCore/43716728291958a4bbe278720c85aef13cb8c248/Other/logo.png -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Cryptor", 6 | "repositoryURL": "https://github.com/IBM-Swift/BlueCryptor.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "6e83ae419817e7272f2f80a7a005a26df366dd8e", 10 | "version": "1.0.31" 11 | } 12 | }, 13 | { 14 | "package": "Socket", 15 | "repositoryURL": "https://github.com/IBM-Swift/BlueSocket.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "49cab699e9f151eeb870ab93d14642425e824c19", 19 | "version": "1.0.49" 20 | } 21 | }, 22 | { 23 | "package": "SSLService", 24 | "repositoryURL": "https://github.com/IBM-Swift/BlueSSLService.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "de36b4d078a12fffba982d17f59d2b7ca587bec9", 28 | "version": "1.0.49" 29 | } 30 | }, 31 | { 32 | "package": "Console", 33 | "repositoryURL": "https://github.com/vapor/console.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "74cfbea629d4aac34a97cead2447a6870af1950b", 37 | "version": "3.1.1" 38 | } 39 | }, 40 | { 41 | "package": "Core", 42 | "repositoryURL": "https://github.com/vapor/core.git", 43 | "state": { 44 | "branch": null, 45 | "revision": "89c6989fd8b1e08acfd198afba1c38971bb814b2", 46 | "version": "3.10.1" 47 | } 48 | }, 49 | { 50 | "package": "Crypto", 51 | "repositoryURL": "https://github.com/vapor/crypto.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "105c2f875588bf40dd24c00cef3644bf8e327770", 55 | "version": "3.4.1" 56 | } 57 | }, 58 | { 59 | "package": "DatabaseKit", 60 | "repositoryURL": "https://github.com/vapor/database-kit.git", 61 | "state": { 62 | "branch": null, 63 | "revision": "8f352c8e66dab301ab9bfef912a01ce1361ba1e4", 64 | "version": "1.3.3" 65 | } 66 | }, 67 | { 68 | "package": "HTTP", 69 | "repositoryURL": "https://github.com/vapor/http.git", 70 | "state": { 71 | "branch": null, 72 | "revision": "0464b715a4b59f54078bcf7a4b424767b03db5a5", 73 | "version": "3.4.0" 74 | } 75 | }, 76 | { 77 | "package": "LoggerAPI", 78 | "repositoryURL": "https://github.com/IBM-Swift/LoggerAPI.git", 79 | "state": { 80 | "branch": null, 81 | "revision": "e29073bb7cecf3673e56bcb16180e8fd0cb091f6", 82 | "version": "1.8.1" 83 | } 84 | }, 85 | { 86 | "package": "Multipart", 87 | "repositoryURL": "https://github.com/vapor/multipart.git", 88 | "state": { 89 | "branch": null, 90 | "revision": "fb216c5a8ef07dcd90aec8a4155e86c831acce97", 91 | "version": "3.1.3" 92 | } 93 | }, 94 | { 95 | "package": "Routing", 96 | "repositoryURL": "https://github.com/vapor/routing.git", 97 | "state": { 98 | "branch": null, 99 | "revision": "d76f339c9716785e5079af9d7075d28ff7da3d92", 100 | "version": "3.1.0" 101 | } 102 | }, 103 | { 104 | "package": "SendGrid", 105 | "repositoryURL": "https://github.com/vapor-community/sendgrid-provider.git", 106 | "state": { 107 | "branch": null, 108 | "revision": "4fca9d02fee4f343666e73651fedd4d26ed048e8", 109 | "version": "3.0.6" 110 | } 111 | }, 112 | { 113 | "package": "Service", 114 | "repositoryURL": "https://github.com/vapor/service.git", 115 | "state": { 116 | "branch": null, 117 | "revision": "fa5b5de62bd68bcde9a69933f31319e46c7275fb", 118 | "version": "1.0.2" 119 | } 120 | }, 121 | { 122 | "package": "swift-nio", 123 | "repositoryURL": "https://github.com/apple/swift-nio.git", 124 | "state": { 125 | "branch": null, 126 | "revision": "546610d52b19be3e19935e0880bb06b9c03f5cef", 127 | "version": "1.14.4" 128 | } 129 | }, 130 | { 131 | "package": "swift-nio-ssl", 132 | "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", 133 | "state": { 134 | "branch": null, 135 | "revision": "0f3999f3e3c359cc74480c292644c3419e44a12f", 136 | "version": "1.4.0" 137 | } 138 | }, 139 | { 140 | "package": "swift-nio-ssl-support", 141 | "repositoryURL": "https://github.com/apple/swift-nio-ssl-support.git", 142 | "state": { 143 | "branch": null, 144 | "revision": "c02eec4e0e6d351cd092938cf44195a8e669f555", 145 | "version": "1.0.0" 146 | } 147 | }, 148 | { 149 | "package": "swift-nio-zlib-support", 150 | "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", 151 | "state": { 152 | "branch": null, 153 | "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", 154 | "version": "1.0.0" 155 | } 156 | }, 157 | { 158 | "package": "SwiftSMTP", 159 | "repositoryURL": "https://github.com/IBM-Swift/Swift-SMTP.git", 160 | "state": { 161 | "branch": null, 162 | "revision": "23360cff5fcb92fb37041f5dd1ef16d7b8fe5ff0", 163 | "version": "5.1.1" 164 | } 165 | }, 166 | { 167 | "package": "TemplateKit", 168 | "repositoryURL": "https://github.com/vapor/template-kit.git", 169 | "state": { 170 | "branch": null, 171 | "revision": "4370aa99c01fc19cc8272b67bf7204b2d2063680", 172 | "version": "1.5.0" 173 | } 174 | }, 175 | { 176 | "package": "URLEncodedForm", 177 | "repositoryURL": "https://github.com/vapor/url-encoded-form.git", 178 | "state": { 179 | "branch": null, 180 | "revision": "20f68fbe7fac006d4d0617ea4edcba033227359e", 181 | "version": "1.1.0" 182 | } 183 | }, 184 | { 185 | "package": "Validation", 186 | "repositoryURL": "https://github.com/vapor/validation.git", 187 | "state": { 188 | "branch": null, 189 | "revision": "4de213cf319b694e4ce19e5339592601d4dd3ff6", 190 | "version": "2.1.1" 191 | } 192 | }, 193 | { 194 | "package": "Vapor", 195 | "repositoryURL": "https://github.com/vapor/vapor.git", 196 | "state": { 197 | "branch": null, 198 | "revision": "642f3d4d1f0eafad651c85524d0d1c698b55399f", 199 | "version": "3.3.3" 200 | } 201 | }, 202 | { 203 | "package": "Mailgun", 204 | "repositoryURL": "https://github.com/twof/VaporMailgunService.git", 205 | "state": { 206 | "branch": null, 207 | "revision": "9c41e744bced6f2f854bd3632333d57d6db46d51", 208 | "version": "1.8.1" 209 | } 210 | }, 211 | { 212 | "package": "VaporTestTools", 213 | "repositoryURL": "https://github.com/LiveUI/VaporTestTools.git", 214 | "state": { 215 | "branch": null, 216 | "revision": "135d02e2e2a632c134567754d65ce2afe262bab3", 217 | "version": "0.1.7" 218 | } 219 | }, 220 | { 221 | "package": "WebSocket", 222 | "repositoryURL": "https://github.com/vapor/websocket.git", 223 | "state": { 224 | "branch": null, 225 | "revision": "d85e5b6dce4d04065865f77385fc3324f98178f6", 226 | "version": "1.1.2" 227 | } 228 | } 229 | ] 230 | }, 231 | "version": 1 232 | } 233 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "MailCore", 6 | products: [ 7 | .library(name: "MailCore", targets: ["MailCore"]), 8 | .library(name: "MailCoreTestTools", targets: ["MailCoreTestTools"]) 9 | ], 10 | dependencies: [ 11 | .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), 12 | .package(url: "https://github.com/twof/VaporMailgunService.git", .upToNextMinor(from: "1.8.0")), 13 | .package(url: "https://github.com/vapor-community/sendgrid-provider.git", from: "3.0.5"), 14 | .package(url: "https://github.com/IBM-Swift/Swift-SMTP.git", from: "5.1.0"), 15 | .package(url: "https://github.com/IBM-Swift/LoggerAPI.git", .upToNextMinor(from: "1.8.0")), 16 | .package(url: "https://github.com/LiveUI/VaporTestTools.git", from: "0.1.5") 17 | ], 18 | targets: [ 19 | .target(name: "MailCore", dependencies: [ 20 | "Vapor", 21 | "Mailgun", 22 | "SendGrid", 23 | "SwiftSMTP" 24 | ] 25 | ), 26 | .target(name: "MailCoreTestTools", dependencies: [ 27 | "Vapor", 28 | "VaporTestTools", 29 | "MailCore" 30 | ] 31 | ), 32 | .testTarget(name: "MailCoreTests", dependencies: [ 33 | "MailCore", 34 | "MailCoreTestTools", 35 | "VaporTestTools" 36 | ] 37 | ) 38 | ] 39 | ) 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | ## 4 | 5 | [](http://bit.ly/2B0dEyt) 6 | [](https://ci.liveui.io/job/LiveUI/job/MailCore/) 7 | [](https://github.com/LiveUI/Boost) 8 | [](https://swift.org/package-manager/) 9 | [](http://swift.org) 10 | [](https://vapor.codes) 11 | 12 | 13 | Mailing wrapper for multiple mailing services like Mailgun, SendGrid or SMTP 14 | 15 | # Features 16 | 17 | - [x] Mailgun 18 | - [x] SendGrid 19 | - [x] SMTP 20 | - [ ] Attachments 21 | - [ ] Multiple emails sent at the same time 22 | - [x] Multiple recipint, CC & BCC fields 23 | 24 | # Install 25 | 26 | Just add following line package to your `Package.swift` file. 27 | 28 | ```swift 29 | .package(url: "https://github.com/LiveUI/MailCore.git", .branch("master")) 30 | ``` 31 | 32 | # Usage 33 | 34 | Usage is really simple mkey! 35 | 36 | ## 1/3) Configure 37 | 38 | First create your client configuration: 39 | 40 | #### Mailgun 41 | 42 | ```swift 43 | let config = Mailer.Config.mailgun(key: "{mailgunApi}", domain: "{mailgunDomain}", region: "{mailgunRegion}") 44 | ``` 45 | 46 | #### SendGrid 47 | 48 | ```swift 49 | let config = Mailer.Config.sendGrid(key: "{sendGridApiKey}") 50 | ``` 51 | 52 | #### SMTP 53 | 54 | Use the `SMTP` struct as a handle to your SMTP server: 55 | 56 | ```swift 57 | let smtp = SMTP(hostname: "smtp.gmail.com", // SMTP server address 58 | email: "user@gmail.com", // username to login 59 | password: "password") // password to login 60 | 61 | let config = Mailer.Config.smtp(smtp) 62 | ``` 63 | 64 | #### SMTP using TLS 65 | 66 | All parameters of `SMTP` struct: 67 | 68 | ```swift 69 | let smtp = SMTP(hostname: String, 70 | email: String, 71 | password: String, 72 | port: Int32 = 465, 73 | useTLS: Bool = true, 74 | tlsConfiguration: TLSConfiguration? = nil, 75 | authMethods: [AuthMethod] = [], 76 | accessToken: String? = nil, 77 | domainName: String = "localhost", 78 | timeout: UInt = 10) 79 | 80 | let config = Mailer.Config.smtp(smtp) 81 | ``` 82 | 83 | ## 2/3) Register service 84 | 85 | Register and configure the service in your apps `configure` method. 86 | 87 | ```swift 88 | Mailer(config: config, registerOn: &services) 89 | ``` 90 | 91 | `Mailer.Config` is an `enum` and you can choose from any integrated services to be used 92 | 93 | ## 3/3) Send an email 94 | 95 | ```swift 96 | let mail = Mailer.Message(from: "admin@liveui.io", to: "bobby.ewing@southfork.com", subject: "Oil spill", text: "Oooops I did it again", html: "
Oooops I did it again
") 97 | return try req.mail.send(mail).flatMap(to: Response.self) { mailResult in 98 | print(mailResult) 99 | // ... Return your response for example 100 | } 101 | ``` 102 | 103 | # Testing 104 | 105 | Mailcore provides a `MailCoreTestTools` framework which you can import into your tests to get `MailerMock`. 106 | 107 | To register, and potentially override any existing "real" Mailer service, just initialize `MailerMock` with your services. 108 | 109 | ```swift 110 | // Register 111 | MailerMock(services: &services) 112 | 113 | // Retrieve in your tests 114 | let mailer = try! req.make(MailerService.self) as! MailerMock 115 | ``` 116 | 117 | `MailerMock` will store the last used result as well as the received message and request. Structure of the moct can be seen below: 118 | 119 | ```swift 120 | public class MailerMock: MailerService { 121 | 122 | public var result: Mailer.Result = .success 123 | public var receivedMessage: Mailer.Message? 124 | public var receivedRequest: Request? 125 | 126 | // MARK: Initialization 127 | 128 | @discardableResult public init(services: inout Services) { 129 | services.remove(type: Mailer.self) 130 | services.register(self, as: MailerService.self) 131 | } 132 | 133 | // MARK: Public interface 134 | 135 | public func send(_ message: Mailer.Message, on req: Request) throws -> Future