Skip to content

Commit 4bedf72

Browse files
committed
SMTP + better readme
1 parent 608f954 commit 4bedf72

File tree

6 files changed

+213
-18
lines changed

6 files changed

+213
-18
lines changed

Package.resolved

Lines changed: 57 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ let package = Package(
1111
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0-rc.2"),
1212
.package(url: "https://github.com/twof/VaporMailgunService.git", from: "0.4.0"),
1313
.package(url: "https://github.com/vapor-community/sendgrid-provider.git", from: "3.0.1"),
14+
.package(url: "https://github.com/IBM-Swift/Swift-SMTP.git", from: "3.0.0"),
1415
.package(url: "https://github.com/LiveUI/VaporTestTools.git", .branch("master"))
1516
],
1617
targets: [
1718
.target(name: "MailCore", dependencies: [
1819
"Vapor",
1920
"Mailgun",
20-
"SendGrid"
21+
"SendGrid",
22+
"SwiftSMTP"
2123
]
2224
),
2325
.target(name: "MailCoreTestTools", dependencies: [

README.md

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Mailing wrapper for multiple mailing services like MailGun, SendGrig or SMTP
1616

1717
- [x] MailGun
1818
- [x] SendGrid
19-
- [ ] SMTP
19+
- [x] SMTP
2020

2121
## Install
2222

@@ -26,24 +26,64 @@ Just add following line package to your `Package.swift` file.
2626
.package(url: "https://github.com/LiveUI/MailCore.git", .branch("master"))
2727
```
2828

29-
## Use
29+
## Usage
3030

3131
Usage is really simple. First register the service in your apps `configure` method:
3232

33+
#### Mailgun
34+
3335
```swift
34-
// Mailgun
3536
let config = Mailer.Config.mailgun(key: "{mailGunApi}", domain: "{mailGunDomain}")
37+
```
38+
39+
#### SendGrid
3640

37-
// or SendGrid
41+
```swift
3842
let config = Mailer.Config.sendGrid(key: "{sendGridApiKey}")
43+
```
44+
45+
#### SMTP
46+
47+
Use the `SMTP` struct as a handle to your SMTP server:
48+
49+
```swift
50+
let smtp = SMTP(hostname: "smtp.gmail.com", // SMTP server address
51+
email: "[email protected]", // username to login
52+
password: "password") // password to login
53+
54+
let config = Mailer.Config.smtp(smtp)
55+
```
3956

40-
// Register and configure the service
57+
<b>Using TLS:</b>
58+
59+
All parameters of `SMTP` struct:
60+
61+
```swift
62+
let smtp = SMTP(hostname: String,
63+
email: String,
64+
password: String,
65+
port: Int32 = 465,
66+
useTLS: Bool = true,
67+
tlsConfiguration: TLSConfiguration? = nil,
68+
authMethods: [AuthMethod] = [],
69+
accessToken: String? = nil,
70+
domainName: String = "localhost",
71+
timeout: UInt = 10)
72+
73+
let config = Mailer.Config.smtp(smtp)
74+
```
75+
76+
#### Register service
77+
78+
Register and configure the service.
79+
80+
```swift
4181
Mailer(config: config, registerOn: &services)
4282
```
4383

4484
`Mailer.Config` is an `enum` and you can choose from any integrated services to be used
4585

46-
And send an email:
86+
#### Send an email
4787

4888
```swift
4989
let mail = Mailer.Message(from: "[email protected]", to: "[email protected]", subject: "Oil spill", text: "Oooops I did it again", html: "<p>Oooops I did it again</p>")
@@ -53,6 +93,53 @@ return try req.mail.send(mail).flatMap(to: Response.self) { mailResult in
5393
}
5494
```
5595

96+
## Testing
97+
98+
Mailcore provides a `MailCoreTestTools` framework which you can import into your tests to get `MailerMock`.
99+
100+
To register, and potentially override any existing "real" Mailer service, just initialize `MailerMock` with your services.
101+
102+
```swift
103+
// Register
104+
MailerMock(services: &services)
105+
106+
// Retrieve in your tests
107+
let mailer = try! req.make(MailerService.self) as! MailerMock
108+
```
109+
110+
`MailerMock` will store the last used result as well as the received message and request. Structure of the moct can be seen below:
111+
112+
```swift
113+
public class MailerMock: MailerService {
114+
115+
public var result: Mailer.Result = .success
116+
public var receivedMessage: Mailer.Message?
117+
public var receivedRequest: Request?
118+
119+
// MARK: Initialization
120+
121+
@discardableResult public init(services: inout Services) {
122+
services.remove(type: Mailer.self)
123+
services.register(self, as: MailerService.self)
124+
}
125+
126+
// MARK: Public interface
127+
128+
public func send(_ message: Mailer.Message, on req: Request) throws -> Future<Mailer.Result> {
129+
receivedMessage = message
130+
receivedRequest = req
131+
return req.eventLoop.newSucceededFuture(result: result)
132+
}
133+
134+
public func clear() {
135+
result = .success
136+
receivedMessage = nil
137+
receivedRequest = nil
138+
}
139+
140+
}
141+
```
142+
56143
## Support
57144

58145
Join our [Slack](http://bit.ly/2B0dEyt), channel <b>#help-boost</b> to ... well, get help :)
@@ -70,6 +157,12 @@ Core package for <b>[Boost](http://www.boostappstore.com)</b>, a completely open
70157
* [DBCore](https://github.com/LiveUI/DbCore/) - Set of tools for work with PostgreSQL database
71158
* [VaporTestTools](https://github.com/LiveUI/VaporTestTools) - Test tools and helpers for Vapor 3
72159

160+
## Implemented thirdparty providers
161+
162+
* <b>MailGun</b> - https://github.com/twof/VaporMailgunService
163+
* <b>SendGrig</b> - https://github.com/vapor-community/sendgrid-provider
164+
* <b>SMTP</b> - https://github.com/IBM-Swift/Swift-SMTP
165+
73166
## Code contributions
74167

75168
We love PR’s, we can’t get enough of them ... so if you have an interesting improvement, bug-fix or a new feature please don’t hesitate to get in touch. If you are not sure about something before you start the development you can always contact our dev and product team through our Slack.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// Message+SMTP.swift
3+
// MailCore
4+
//
5+
// Created by Ondrej Rafaj on 11/04/2018.
6+
//
7+
8+
import Foundation
9+
import Vapor
10+
import SwiftSMTP
11+
12+
13+
extension Mailer.Message {
14+
15+
func asSmtpMail() -> Mail {
16+
let fromUser = User(email: from)
17+
18+
let toUser = User(email: to)
19+
20+
let attachments: [Attachment]
21+
if let html = html {
22+
attachments = [Attachment(htmlContent: html)]
23+
} else {
24+
attachments = []
25+
}
26+
27+
let mail = Mail(from: fromUser, to: [toUser], subject: subject, text: text, attachments: attachments)
28+
return mail
29+
}
30+
31+
}

Sources/MailCore/MailCore.swift

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,27 @@ import Foundation
99
import Vapor
1010
import Mailgun
1111
import SendGrid
12+
@_exported import SwiftSMTP
1213

1314

15+
/// Emailing service
1416
public protocol MailerService: Service {
1517
func send(_ message: Mailer.Message, on req: Request) throws -> Future<Mailer.Result>
1618
}
1719

1820

21+
/// Mailer class
1922
public class Mailer: MailerService {
2023

24+
/// Basic message
2125
public struct Message {
2226
public let from: String
2327
public let to: String
2428
public let subject: String
2529
public let text: String
2630
public let html: String?
2731

32+
/// Message init
2833
public init(from: String, to: String, subject: String, text: String, html: String? = nil) {
2934
self.from = from
3035
self.to = to
@@ -34,23 +39,28 @@ public class Mailer: MailerService {
3439
}
3540
}
3641

42+
/// Result returned by the services
3743
public enum Result {
3844
case serviceNotConfigured
3945
case success
4046
case failure(error: Error)
4147
}
4248

49+
/// Service configuration
4350
public enum Config {
4451
case none
4552
case mailgun(key: String, domain: String)
4653
case sendGrid(key: String)
54+
case smtp(SMTP)
4755
}
4856

49-
let config: Config
57+
/// Current email service configuration
58+
var config: Config
5059

5160

5261
// MARK: Initialization
5362

63+
/// Mailer initialization. MailerService get's registered to the services at this point, there is no need to do that manually!
5464
@discardableResult public init(config: Config, registerOn services: inout Services) throws {
5565
self.config = config
5666

@@ -70,6 +80,7 @@ public class Mailer: MailerService {
7080

7181
// MARK: Public interface
7282

83+
/// Send a message using a provider defined in `config: Config`
7384
public func send(_ message: Message, on req: Request) throws -> Future<Mailer.Result> {
7485
switch config {
7586
case .mailgun(_, _):
@@ -89,15 +100,19 @@ public class Mailer: MailerService {
89100
return Mailer.Result.failure(error: error)
90101
}
91102
)
103+
case .smtp(let smtp):
104+
let promise = req.eventLoop.newPromise(Mailer.Result.self)
105+
smtp.send(message.asSmtpMail()) { error in
106+
if let error = error {
107+
promise.succeed(result: Mailer.Result.failure(error: error))
108+
} else {
109+
promise.succeed(result: Mailer.Result.success)
110+
}
111+
}
112+
return promise.futureResult
92113
default:
93114
return req.eventLoop.newSucceededFuture(result: Mailer.Result.serviceNotConfigured)
94115
}
95116
}
96117

97-
// MARK: Templating
98-
99-
public func template(name: String, params: Codable) -> String {
100-
return ":)"
101-
}
102-
103118
}

Sources/MailCoreTestTools/MailCoreTestTools.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Foundation
99
import Vapor
1010
@testable import Service
11-
import MailCore
11+
@_exported import MailCore
1212
import VaporTestTools
1313

1414

0 commit comments

Comments
 (0)