Skip to content

Commit

Permalink
Refactor SMTPSocket and SMTP with a specifically no-auth constructor.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbeitzel committed Jan 22, 2022
1 parent 6036eb7 commit 1d8fa9b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 7 deletions.
33 changes: 33 additions & 0 deletions Sources/SwiftSMTP/SMTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,39 @@ public struct SMTP {
self.timeout = timeout
}

/// Initializes an `SMTP` instance, specifically for use when communicating with an SMTP
/// host which does not perform authentication.
///
/// - Parameters:
/// - hostname: Hostname of the SMTP server to connect to, i.e. `smtp.example.com`.
/// - port: Port to connect to the server on. Defaults to `465`.
/// - tlsMode: TLSMode `enum` indicating what form of connection security to use.
/// - tlsConfiguration: `TLSConfiguration` used to connect with TLS. If nil, a configuration with no backing
/// certificates is used. See `TLSConfiguration` for other configuration options.
/// - domainName: Client domain name used when communicating with the server. Defaults to `localhost`.
/// - timeout: How long to try connecting to the server to before returning an error. Defaults to `10` seconds.
///
/// - Note:
/// - You may need to enable access for less secure apps for your account on the SMTP server.
/// - Some servers like Gmail support IPv6, and if your network does not, you will first attempt to connect via
/// IPv6, then timeout, and fall back to IPv4. You can avoid this by disabling IPv6 on your machine.
public init(hostname: String,
port: Int32 = 587,
tlsMode: TLSMode = .requireSTARTTLS,
tlsConfiguration: TLSConfiguration? = nil,
domainName: String = "localhost",
timeout: UInt = 10) {
self.hostname = hostname
self.email = ""
self.password = ""
self.port = port
self.tlsMode = tlsMode
self.tlsConfiguration = tlsConfiguration
self.authMethods = [String: AuthMethod]()
self.domainName = domainName
self.timeout = timeout
}

/// Send an email.
///
/// - Parameters:
Expand Down
39 changes: 35 additions & 4 deletions Sources/SwiftSMTP/SMTPSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,40 @@ struct SMTPSocket {
domainName: String,
timeout: UInt) throws {
socket = try Socket.create()
let serverOptions = try setupSocket(hostname: hostname,
port: port,
tlsMode: tlsMode,
tlsConfiguration: tlsConfiguration,
domainName: domainName,
timeout: timeout)
let authMethod = try getAuthMethod(authMethods: authMethods, serverOptions: serverOptions, hostname: hostname)
try login(authMethod: authMethod, email: email, password: password)
}


/// Initializer for an SMTPSocket when you want to connect to a server that does not
/// require authentication to send messages.
init(hostname: String,
port: Int32,
tlsMode: SMTP.TLSMode,
tlsConfiguration: TLSConfiguration?,
domainName: String,
timeout: UInt) throws {
socket = try Socket.create()
_ = try setupSocket(hostname: hostname,
port: port,
tlsMode: tlsMode,
tlsConfiguration: tlsConfiguration,
domainName: domainName,
timeout: timeout)
}

private func setupSocket(hostname: String,
port: Int32,
tlsMode: SMTP.TLSMode,
tlsConfiguration: TLSConfiguration?,
domainName: String,
timeout: UInt) throws -> [Response] {
if tlsMode == .requireTLS {
if let tlsConfiguration = tlsConfiguration {
socket.delegate = try tlsConfiguration.makeSSLService()
Expand All @@ -48,10 +82,7 @@ struct SMTPSocket {
throw SMTPError.requiredSTARTTLS
}
}
let authMethod = try getAuthMethod(authMethods: authMethods, serverOptions: serverOptions, hostname: hostname)
if authMethod != .none {
try login(authMethod: authMethod, email: email, password: password)
}
return serverOptions
}

func write(_ text: String) throws {
Expand Down
17 changes: 17 additions & 0 deletions Tests/SwiftSMTPTests/TestMailSender.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ class TestMailSender: XCTestCase {
x.fulfill()
}
}

func testSendMailNoAuth() throws {
let x = expectation(description: #function)
defer { waitForExpectations(timeout: testDuration) }

let mail = Mail(from: from, to: [to], subject: #function, text: text)
if let theHost = noAuthHost {
let noAuthSMTP = SMTP(hostname: theHost, port: noAuthPort, tlsMode: .ignoreTLS,
tlsConfiguration: .none)
noAuthSMTP.send(mail) { (err) in
XCTAssertNil(err, String(describing: err))
x.fulfill()
}
} else {
throw XCTSkip("No no-auth SMTP server configured")
}
}

func testSendMailInArray() {
let x = expectation(description: #function)
Expand Down
3 changes: 0 additions & 3 deletions Tests/SwiftSMTPTests/TestSMTPSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,9 @@ class TestSMTPSocket: XCTestCase {
do {
_ = try SMTPSocket(
hostname: noAuthHost,
email: email,
password: "don't care",
port: noAuthPort,
tlsMode: .ignoreTLS,
tlsConfiguration: nil,
authMethods: [String: AuthMethod](),
domainName: domainName,
timeout: timeout
)
Expand Down

0 comments on commit 1d8fa9b

Please sign in to comment.