Git Product home page Git Product logo

swift-smtp's Introduction

Swift-SMTP

Swift-SMTP bird

Swift SMTP client.

Build Status macOS Linux Apache 2

Features

  • Connect securely through SSL/TLS when needed
  • Authenticate with CRAM-MD5, LOGIN, PLAIN, or XOAUTH2
  • Send emails with local file, HTML, and raw data attachments
  • Add custom headers
  • Documentation

Swift Version

macOS & Linux: Swift 5.2 or above.

Installation

You can add SwiftSMTP to your project using Swift Package Manager. If your project does not have a Package.swift file, create one by running swift package init in the root directory of your project. Then open Package.swift and add SwiftSMTP as a dependency. Be sure to add it to your desired targets as well:

// swift-tools-version:4.0

import PackageDescription

let package = Package(
    name: "MyProject",
    products: [
        .library(
            name: "MyProject",
            targets: ["MyProject"]),
    ],
    dependencies: [
        .package(url: "https://github.com/Kitura/Swift-SMTP", .upToNextMinor(from: "5.1.0")),    // add the dependency
    ],
    targets: [
        .target(
            name: "MyProject",
            dependencies: ["SwiftSMTP"]),                                                           // add targets
        .testTarget(                                                                                // note "SwiftSMTP" (NO HYPHEN)
            name: "MyProjectTests",
            dependencies: ["MyProject"]),
    ]
)

After adding the dependency and saving, run swift package generate-xcodeproj in the root directory of your project. This will fetch dependencies and create an Xcode project which you can open and begin editing.

Migration Guide

Version 5.0.0 brings breaking changes. See the quick migration guide here.

Usage

Initialize an SMTP instance:

import SwiftSMTP

let smtp = SMTP(
    hostname: "smtp.gmail.com",     // SMTP server address
    email: "[email protected]",        // username to login
    password: "password"            // password to login
)

TLS

Additional parameters of SMTP struct:

public init(hostname: String,
            email: String,
            password: String,
            port: Int32 = 587,
            tlsMode: TLSMode = .requireSTARTTLS,
            tlsConfiguration: TLSConfiguration? = nil,
            authMethods: [AuthMethod] = [],
            domainName: String = "localhost",
            timeout: UInt = 10)

By default, the SMTP struct connects on port 587 and sends mail only if a TLS connection can be established. It also uses a TLSConfiguration that uses no backing certificates. View the docs for more configuration options.

Send email

Create a Mail object and use your SMTP handle to send it. To set the sender and receiver of an email, use the User struct:

let drLight = Mail.User(name: "Dr. Light", email: "[email protected]")
let megaman = Mail.User(name: "Megaman", email: "[email protected]")

let mail = Mail(
    from: drLight,
    to: [megaman],
    subject: "Humans and robots living together in harmony and equality.",
    text: "That was my ultimate wish."
)

smtp.send(mail) { (error) in
    if let error = error {
        print(error)
    }
}

Add Cc and Bcc:

let roll = Mail.User(name: "Roll", email: "[email protected]")
let zero = Mail.User(name: "Zero", email: "[email protected]")

let mail = Mail(
    from: drLight,
    to: [megaman],
    cc: [roll],
    bcc: [zero],
    subject: "Robots should be used for the betterment of mankind.",
    text: "Any other use would be...unethical."
)

smtp.send(mail)

Send attachments

Create an Attachment, attach it to your Mail, and send it through the SMTP handle. Here's an example of how you can send the three supported types of attachments--a local file, HTML, and raw data:

// Create a file `Attachment`
let fileAttachment = Attachment(
    filePath: "~/img.png",          
    // "CONTENT-ID" lets you reference this in another attachment
    additionalHeaders: ["CONTENT-ID": "img001"]
)

// Create an HTML `Attachment`
let htmlAttachment = Attachment(
    htmlContent: "<html>Here's an image: <img src=\"cid:img001\"/></html>",
    // To reference `fileAttachment`
    related: [fileAttachment]
)

// Create a data `Attachment`
let data = "{\"key\": \"hello world\"}".data(using: .utf8)!
let dataAttachment = Attachment(
    data: data,
    mime: "application/json",
    name: "file.json",
    // send as a standalone attachment
    inline: false   
)

// Create a `Mail` and include the `Attachment`s
let mail = Mail(
    from: from,
    to: [to],
    subject: "Check out this image and JSON file!",
    // The attachments we created earlier
    attachments: [htmlAttachment, dataAttachment]
)

// Send the mail
smtp.send(mail)

/* Each type of attachment has additional parameters for further customization */

Send multiple mails

let mail1: Mail = //...
let mail2: Mail = //...

smtp.send([mail1, mail2],
    // This optional callback gets called after each `Mail` is sent.
    // `mail` is the attempted `Mail`, `error` is the error if one occured.
    progress: { (mail, error) in
    },

    // This optional callback gets called after all the mails have been sent.
    // `sent` is an array of the successfully sent `Mail`s.
    // `failed` is an array of (Mail, Error)--the failed `Mail`s and their corresponding errors.
    completion: { (sent, failed) in
    }
)

Acknowledgements

Inspired by Hedwig and Perfect-SMTP.

License

Apache v2.0

swift-smtp's People

Contributors

dannys42 avatar djones6 avatar hanskroner avatar ianpartridge avatar quanvo87 avatar rafiki270 avatar sanzaru avatar vitkabele avatar youming-lin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swift-smtp's Issues

Swift 4

Any chance we can update Package.swift for Swift 4? Most of the other Kitura packages have already been updated.

No anonymous authentication?

I'm using an SMTP server that doesn't require authentication, though when Swift-SMTP attempts to authenticate with empty credentials, it fails.

I'm having no issues at all sending mail anonymously with the swaks tool.

How do I specify a credential-less SMTP configuration?

Unit test needs new testing credentials

Current unit tests fail due to email test credentials.

The current credentials are failing, presumably because IBM probably shut down the email account they had been using for test. Need to evaluate the requirements for the test setup and provide new credentials to get tests to pass.

Swift-SMTP interoperability problem with Yahoo SMTP for 8k+ attachments

I'm not sure whether this problem with worthy of your attention, since (so far) it seems to be specific to one email provider and for large attachments only. But I thought I'd report it in case more providers are affected.

When sending an attachment of size 8k+ from my Yahoo account and using smtp.mail.yahoo.com as my SMTP server, I get the following error message:

Bad response received for command. command: (
.), response: 500 Line length exceeded. See RFC 2821 #4.5.3.1.

Sending an attachment of size 4k via Yahoo succeeds.

Sending an attachment of size 8k via Mac/iCloud SMTP infrastructure succeeds.

This is in a MacOS app with the following version information:

Swift 4.2
Xcode 10.1
MacOS 10.14.2
SwiftSMTP 5.1.0
LoggerAPI 1.8.0
Cryptor 1.0.23
SSLService 1.0.44
Socket 1.0.44

Below is my "send email" code showing full parameters from my test MacOS project. I have a test project if that is helpful.

Darrell

@IBAction func sendEmailButton(_ sender: NSButton) {
    scrollTextOutlet.string = ""
    let serverHostname = serverHostnameOutlet.stringValue
    let fromAddress = fromAddressOutlet.stringValue
    let fromPassword = fromPasswordOutlet.stringValue
    let toAddress = toAddressOutlet.stringValue
    let smtp = SMTP(hostname: serverHostname, email: fromAddress, password: fromPassword, port: 587, tlsMode: .requireSTARTTLS, tlsConfiguration: nil, authMethods: [], domainName: "localhost")
    let sender = Mail.User(name: "smtp test email user", email: fromAddress)
    let recipient = Mail.User(name: "test recipient", email: toAddress)
    var mail: Mail
    if attachmentCheckbox?.state.rawValue == 1 {
        self.scrollTextOutlet.string += "using attachment \(self.selectedPath)\n"
        let attachment = Attachment(filePath: self.selectedPath)
        mail = Mail(from: sender, to: [recipient], cc: [], bcc: [], subject: "test email subject", text: "test email body", attachments: [attachment], additionalHeaders: [:])

    } else {
        self.scrollTextOutlet.string += "sending email without attachment\n"
        mail = Mail(from: sender, to: [recipient], cc: [], bcc: [], subject: "test email subject", text: "test email body", attachments: [], additionalHeaders: [:])
    }
    smtp.send(mail) { (error) in
        if let error = error {
            self.scrollTextOutlet.string += "email error \(error)\n"
            if let error = error as? SMTPError {
                self.scrollTextOutlet.string += "\(error.description)\n"
            } else {
                self.scrollTextOutlet.string += "\(error.localizedDescription)\n"
            }
        } else {
            self.scrollTextOutlet.string += "test mail sent successfully\n"
        }
    }
}

Tag/Release numbering problem?

I've been trying to fetch v1.1.2 for a project; however, it keeps fetching 1.1.0 instead. Looking at the release and tag listing, I found this strange numbering sequence:

screen shot 2017-09-12 at 5 33 54 pm

Thoughts?

HTML related attachment image not work on gmail mail

Hello I have a face issue when i add html content with related attachment and send it to mail send function Using below CONTENT-ID that work only in iphone mail not in gmail mail. In gmail mail it take as a attachment instead of html src.

// Create a file `Attachment`
let fileAttachment = Attachment(
    filePath: "~/img.png",          
    // "CONTENT-ID" lets you reference this in another attachment
    additionalHeaders: ["CONTENT-ID": "img001"]
)

// Create an HTML `Attachment`
let htmlAttachment = Attachment(
    htmlContent: "<html>Here's an image: <img src=\"cid:img001\"/></html>",
    // To reference `fileAttachment`
    related: [fileAttachment]
)

Thank you
Ruchi

Error with xouath2

Hello,
I want to use Swift SMTP with my g suite gmail account, I created service account, created key in pkcs (p12) format, added it as chainFile and got Error: "bad response" when authenticating with xOuath2.
If I create certificate and private key from p12 file I'm getting, pkcs12 is not specified.
I don't know which certificate to use, which key, can you please provide an example of Swift SMTP with TLS ?

Thank you

Add user friendly info

Like self-signed certs needing a password, and suggestions on how to troubleshoot some error messages.

  • also make password for self signed cert in SSL not optional (will not work without one)

Error when adding to dependencies

First thank you for this awesome library!
So I have done everything like you say but I get this error :

error: dependency 'SwiftSMTP' in target 'Resumos.nosync' requires explicit declaration; provide the name of the package dependency with '.package(name: "SwiftSMTP", url: "https://github.com/IBM-Swift/Swift-SMTP", .upToNextMinor("5.1.0"))' and now I can't install it

Error "Operation now in progress" on Ubuntu

I'm having trouble connecting to a Postfix mailserver running on a local Ubuntu 16.04 machine using Swift-SMTP 1.1.3. The SMTP server uses no authentication and it is configured like this:

let smtp = SMTP(
    hostname: "127.0.0.1",
    email: "",
    password: "",
    port: 587
)

When trying to send an e-mail, an error (Error code: -9989(0x-2705), Operation now in progress) is thrown. Interestingly, the error remains the same when I change the port to another invalid port.

The SMTP settings are correct. Another application on the same machine is using the Postfix server, which is working fine, and I can telnet 127.0.0.1 587 and get an EHLO response.

What could be going wrong?

vapor xcode failed

vapor xcode failed

Generating Xcode Project [Failed]
error: multiple products named 'Logging' in: Console, swift-log
error: multiple targets named 'Logging' in: Console, swift-log

Error: Could not generate Xcode project: error: multiple products named 'Logging' in: Console, swift-log
error: multiple targets named 'Logging' in: Console, swift-log

Package.swift

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "NewBox",
    products: [
        .library(name: "NewBox", targets: ["App"]),
    ],
    dependencies: [
        // ๐Ÿ’ง A server-side Swift web framework.
         .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),

        // mail Server
        .package(url: "https://github.com/IBM-Swift/Swift-SMTP.git", from: "5.1.0")

    ],
    targets: [
        .target(name: "App", dependencies: [ "SwiftSMTP", "Vapor"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

Add requireTLS

From nodemailer:

requireTLS โ€“ if this is true and secure is false then Nodemailer tries to use STARTTLS even if the server does not advertise support for it. If the connection can not be encrypted then message is not sent

Error code: -9968(0x26f0), Operation now in progress

I am trying to send mail through Zoho Mail using Swift-SMTP as part of a Vapor app on a Linux server.
I am sending the mail in the background thread once triggered using a HTTP request.

DispatchQueue.global().async {
    smtp.send(email){
        if let error = error{
            print(error)
        }
    }
}

The console prints out an annoyingly unhelpful "Error code: -9968(0x26f0), Operation now in progress". Please can you help me to decipher the meaning of this?

Add retry on login failure

Logging in to an SMTP server fails intermittently, maybe because SMTP servers don't like someone logging in so much/quickly, which is what the tests do.

Adding a retry feature could be helpful, or a delay between tests.

Way to define either TLS or SSL

Hi! I tried to find in documentation a way to use ssl or tls option for sending mails. Is there any way except to define 465 or 587 port? Because I want have an options to define a port and tls separately. Does anyone have any suggestions?

I've asked because I could not send to gmail smtp by 465 port
only through 587

Could you provide an example with TSL or SSL?

I'm testing Swift-SMTP with Gmail in two situations. (less secure app access is on and off)

Swift-SMTP version: 5.1.0

  • 1)less secure app access is on
    The Swift-SMTP works very well
  • 2)less secure app access is off
    The Swift-SMTP will cause an issue, please refer to following

So, could you provide an example for situation 2

issue with gmail (when less secure app access is off)

Bad response received for command. command: (ZXdvdGRnYWJEVw==), response: 534-5.7.9 Application-specific password required.

CI failure with Swift 5

#93 attempts to add Swift 5 coverage to CI, however one of the tests fails on Linux with:

/home/travis/build/IBM-Swift/Swift-SMTP/Tests/SwiftSMTPTests/TestMiscellaneous.swift:82: error: TestMiscellaneous.testMailHeaders : XCTAssertTrue failed - Message-Id header missing or invalid

This needs some investigation.

send email from gmail not working

I can't send email from my gmail account with following code:
`
import SwiftSMTP

public final class SwiftToolBoxCore {
public func send() -> Void {
let smtp = SMTP(
hostname: "smtp.gmail.com",
email: "[email protected]",
password: "mypassword",
tlsMode: .requireSTARTTLS
)

    let fromUser = Mail.User(
        name: "- -",
        email: "[email protected]"
    )
    let toUser = Mail.User(
        email: "[email protected]"
    )

    let mail = Mail(
        from: fromUser,
        to: [toUser],
        subject: "subject",
        text: "content text"
    )

    smtp.send(mail) { (error) in
        if let error = error {
            print(error)
        }
    }
}

}
`

There is no error message. Not secure apps are allowed on my gmail account. What I am doing wrong?

Swift-SMTP breaks simulator

I followed the instructions provided exactly to add the library to a brand new project (only has a button and an outlet for it) but after running swift package generate-xcodeproj there's now two simulators for each device: e.g. "iPhone SE (12.0)" and "iPhone SE 12.4".

No matter which one I pick the simulator doesn't open anymore.
Building is still successful but the simulator simply doesn't open and I noticed that the "Executable" (Product - Scheme - Edit Scheme - Run - Info) is set to "None" and doesn't give me a "*.app" choice.

Cleaning, restarting,... didn't work and deleting this project and doing it all over again came to the same result. Btw, the simulator works fine in other projects that use CocoaPods with other libraries.

@quanvo87 Any idea what's going on here and how I fix it?

Mail declined by recipient: Syntax error - line too long

I cannot send emails to some email addresses. They are rejected with the following message:

Syntax error - line too long

and some more info from here:

Action: failed
Status: 5.0.0
Remote-MTA: DNS; mx-ha02.web.de [212.227.17.8]
Diagnostic-Code: SMTP; 501 Syntax error - line too long
Last-Attempt-Date:
Final-Log-ID: i04d66w419XirMM

Any idea what I need to do?

Could not generate Xcode project: error: multiple products named 'Logging' in: Console, swift-log

At first thank you so much about generate and maintain this library. Your work is awesome!

I need some improvements on the naming of your LogginAPI.
If I try to use this Swift-SMTP library with my vapor project, I receive this error:

"Could not generate Xcode project: error: multiple products named 'Logging' in: Console, swift-log"

It's happens when I add this package
.package(url: "https://github.com/IBM-Swift/Swift-SMTP", from: "5.1.1")

I can solve it using other dependency of your LogginAPI

.package(url: "https://github.com/IBM-Swift/LoggerAPI.git", .upToNextMinor(from: "1.8.0")),
.package(url: "https://github.com/IBM-Swift/Swift-SMTP", from: "5.1.1")

And now is working, but the idea is only need one package and inside it have the last version of each one.

Thank you in advance

Allow headers to be replaced

I tried sending an email formatted as HTML, by including an extra header:

additionalHeaders: [(header: "Content-Type", value: "text/html")]

However, we get this error:

554 Transaction failed: Duplicate header 'Content-Type'.

It looks like SMTPSocket is still sending Content-Type: text/plain along with the new header, which is invalid.

Is there a way we can update the API to overwrite headers rather than just appending them? Or, for my specific use case, an alternative method for sending HTML emails?

Update Cryptor

Cryptor is on version 1.0.2 now with fixed swift 4.1 warnings

Omission of STARTTLS

This relates to PR #78 which I have closed for now in favour of an issue for discussion.

I had a bit of a misunderstanding in the migration guide of what this library is expecting to be the behaviour of SMTP/S and STARTTLS which is incorrect.

SMTP over 465 is deprecated/legacy, some references:

And 465 has been reissued by IANA as well, with many modern mail servers no longer listening on 465 by default.

I can't see a problem with supporting a direct TLS connection at all, I'm not asking this be removed, but STARTTLS is the modern standard and this library should really be supporting it in my opinion.

It was mentioned in the PR that this functionality was removed as the force TLS upgrade was causing issues for some users, but this is exactly how STARTTLS should work if the server requests the TLS upgrade, so maybe I've misunderstood that comment too and there was something else going on?

By the STARTTLS spec, after the commands are issued the existing socket negotiates TLS, effectively upgrading the existing socket to TLS. By the comment #62 (comment) and what I saw in
version 2 of this library, the socket was instead being closed and reopened on 465, which is effectively just ignoring the STARTTLS negotiation in favour of a direct connection on port 465, this may have been why users were seeing issues where they had servers not listening on 465.

Message-Id improperly formatted

Problem:
Based on the current MESSAGE-ID format (as of v1.0.8), messages sent via Swift-SMTP are being marked as spam.

For example, Google changes the MESSAGE-ID value from
C3740F09-A2C0-4A84-A382-85FE08C87556.Swift-SMTP
for Gmail recipients to
<[email protected]>
and sends the message to the spam folder.

The correct format for the MESSAGE-ID field, as specified in RFC 5322, is:

message-id = "Message-ID:" msg-id CRLF
...
msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]

id-left = dot-atom-text / obs-id-left

id-right = dot-atom-text / no-fold-literal / obs-id-right

"dot-atom-text" represents text, followed by a ".", followed by more text.

Solution:
To prevent Swift-SMTP messages from being marked as spam due to incorrect formatting, I propose coding the MESSAGE-ID field to contain a value like the following:
<[email protected]>

SSLService.Configuration compile errors on macOS

Seeing these compile errors for the SwiftSMTP module since updating my project dependencies:

.../Sources/SwiftSMTP/TLSConfiguration.swift:33:36: 'init(withCipherSuite:clientAllowsSelfSignedCertificates:)' is unavailable: This API not supported on Apple platforms.

.../Sources/SwiftSMTP/TLSConfiguration.swift:53:36: 'init(withCACertificateFilePath:usingCertificateFile:withKeyFile:usingSelfSignedCerts:cipherSuite:)' is unavailable: This API not supported on Apple platforms.

.../Sources/SwiftSMTP/TLSConfiguration.swift:78:36: 'init(withCACertificateDirectory:usingCertificateFile:withKeyFile:usingSelfSignedCerts:cipherSuite:)' is unavailable: This API not supported on Apple platforms.

Believe this may be related to a recent change in BlueSSLService 1.0.40. (The previous working version in Package.resolved was BlueSSLService 1.0.25).

To avoid confusion regarding the availability of SSLService.Configuration APIs on supported platforms, added @available attributes to all the APIs that are only supported on the Linux platform. This will cause compile time errors if the wrong API is used on Apple platforms.

Connecting to Amazon SES

Hey @quanvo87, I've been having a hard time connecting to Amazon SES. Here's how I'm connecting:

let smtp = SMTP(hostname: "email-smtp.us-west-2.amazonaws.com",
                email: MY_SES_USERNAME,
                password: MY_SES_PASSWORD,
                port: 587)

With port 587, I get this error:

530 Must issue a STARTTLS command first

If I change the port to 465 (TLS Wrapper instead of STARTTLS), it just times out instead of connecting.

Any ideas? Everything works from the command line, so it's not a firewall issue. Thanks!

Why are almost all `Mail`-properties internal?

I'm moving an application from the broken Vapor SMTP implementation to this one, and have noticed that almost all properties on a Mail are internal.

E-mails are sent from various places in the application, and we centrally log all sent e-mails into the database. Is there a specific reason why the properties (like from, to, subject and text) are internal?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.