Send email to any SMTP server like a boss, in Swift and cross-platform

Overview

codebeat badge


Hedwig is a Swift package which supplies a set of high level APIs to allow you sending email to an SMTP server easily. If you are planning to send emails from your next amazing Swift server app, Hedwig might be a good choice.

Features

  • Connect to all SMTP servers, through whether plain, SSL or TLS (STARTTLS) port.
  • Authentication with PLAIN, CRAM-MD5, LOGIN or XOAUTH2.
  • Send email with HTML body and attachments.
  • Customize validation method and mail header, to track your mail campaign.
  • Queued mail sending, without blocking your app. You can even send mails concurrently.
  • Works with Swift Package Manager, in the latest Swift syntax and cross-platform.
  • Fully tested and documented.

Installation

Add the url of this repo to your Package.swift:

import PackageDescription

let package = Package(
    name: "YourAwesomeSoftware",
    dependencies: [
        .Package(url: "https://github.com/onevcat/Hedwig.git", 
                 majorVersion: 1)
    ]
)

Then run swift build whenever you get prepared. (Also remember to grab a cup of coffee ๐Ÿ˜„ )

You can find more information on how to use Swift Package Manager in Apple's official page.

Usage

Sending text only email

let hedwig = Hedwig(hostName: "smtp.example.com", user: "[email protected]", password: "password")
let mail = Mail(
        text: "Across the great wall we can reach every corner in the world.", 
        from: "[email protected]", 
        to: "[email protected]", 
        subject: "Hello World"
)
    
hedwig.send(mail) { error in
    if error != nil { /* Error happened */ }
}

Sending HTML email

let hedwig = Hedwig(hostName: "smtp.example.com", user: "[email protected]", password: "password")
let attachment = Attachment(htmlContent: "<html><body><h1>Title</h1><p>Content</p></body></html>")
let mail = Mail(
        text: "Fallback text", 
        from: "[email protected]", 
        to: "[email protected]", 
        subject: "Title", 
        attachments: [attachment]
)
hedwig.send(mail) { error in
    if error != nil { /* Error happened */ }
}

CC and BCC

let hedwig = Hedwig(hostName: "smtp.example.com", user: "[email protected]", password: "password")
let mail = Mail(
        text: "Across the great wall we can reach every corner in the world.", 
        from: "[email protected]", 
        to: "[email protected]",
        cc: "Wei Wang <[email protected]>, [email protected]", // Addresses will be parsed for you
        bcc: "My Group: [email protected], [email protected];",    // Even with group syntax
        subject: "Hello World"
)
hedwig.send(mail) { error in
    if error != nil { /* Error happened */ }
}

Using different SMTP settings (security layer, auth method and etc.)

let hedwig = Hedwig(
        hostName: "smtp.example.com", 
        user: "[email protected]", 
        password: "password",
        port: 1234,     // Determined from secure layer by default
        secure: .plain, // .plain (Port 25) | .ssl (Port 465) | .tls (Port 587) (default)
        validation: .default, // You can set your own certificate/cipher/protocols
        domainName: "onevcat.com", // Used when saying hello to STMP Server
        authMethods: [.plain, .login] // Default: [.plain, .cramMD5, .login, .xOauth2]        
)

Send mails with inline image and other attachment

let imagePath = "/tmp/image.png"
// You can create an attachment from a local file path.
let imageAttachment = Attachment(
        filePath: imagePath, 
        inline: true, 
        // Add "Content-ID" if you need to embed this image to another attachment.
        additionalHeaders: ["Content-ID": "hedwig-image"] 
)
let html = Attachment(
        htmlContent: "<html><body>A photo <img src=\"cid:hedwig-image\"/></body></html>", 
        // If imageAttachment only used embeded in HTML, I recommend to set it as related.
        related: [imageAttachment]
)

// You can also create attachment from raw data.
let data = "{\"key\": \"hello world\"}".data(using: .utf8)!
let json = Attachment(
        data: data, 
        mime: "application/json", 
        name: "file.json", 
        inline: false // Send as standalone attachment.
)

let mail = Mail(
        text: "Fallback text", 
        from: "[email protected]", 
        to: "[email protected]", 
        subject: "Check the photo and json file!",
        attachments: [html, json]
hedwig.send(mail) { error in
    if error != nil { /* Error happened */ }
}

Send multiple mails

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

hedwig.send([mail1, mail2], 
        progress: { (mail, error) in
            if error != nil { 
                print("\(mail) failed. Error: \(error)") 
            }
        },
        completion: { (sent, failed) in
            for mail in sent {
                print("Sent mail: \(mail.messageId)")
            }
            
            for (mail, error) in failed {
                print("Mail \(mail.messageId) errored: \(error)")
            }
        }
)

Help and Questions

Visit the documentation page for full API reference.

You could also run the tests (swift test) to see more examples to know how to use Hedwig.

If you have found the framework to be useful, please consider a donation. Your kind contribution will help me afford more time on the project.

Click here to lend your support to: Hedwig and make a donation at pledgie.com !

Or you are a Bitcoin fan and want to treat me a cup of coffe, here is my wallet address:

1MqwfsxBJ5pJX4Qd2sRVhK3dKTQrWYooG5

FAQ

I cannot send mails with Gmail SMTP.

Gmail uses an application specific password. You need to create one and use the specified password when auth. See this.

I need to add/set some additonal header in the mail.

Both Mail and Attachment accept customizing header fields. Pass your headers as additionalHeaders when creating the mail or attachment and Hedwig will handle it.

Can I use it in iOS?

At this time Swift Package Manager has no support for iOS, watchOS, or tvOS platforms. So the answer is no. But this framework is not using anything only in iOS (like UIKit), so as soon as Swift Package Manager supports iOS, you can use it there too.

Tell me about the name and logo of Hedwig

Yes, Hedwig (bird) was Harry Potter's pet Snowy Owl. The logo of Hedwig (this framework) is created by myself and it pays reverence to the novels and movies.

Other questions

Submit an issue if you find something wrong. Pull requests are warmly welcome, but I suggest to discuss first.

You can also follow and contact me on Twitter or Sina Weibo.

Enjoy sending your emails

License

Hedwig is released under the MIT license. See LICENSE for details.

Comments
  • ๅ‘้€HTML้™„ไปถๆ—ถๅ€™ไนฑ็ 

    ๅ‘้€HTML้™„ไปถๆ—ถๅ€™ไนฑ็ 

    HTML ๆ–‡ไปถๅœจๆ”ถๅˆฐ็š„ๆ—ถๅ€™ไนŸๅชๆœ‰่ฟ™ไธชไนฑ็  AA M a;] ฿ญ QE

    let attachement = Attachment(htmlContent: "<html><body><h1>Title</h1><p>Content</p></body></html>")
      let bot = "cibot@**.net"
      let to = "**@**.net"
      let cc = ""
      let hedwig = Hedwig(hostName: "smtp.exmail.qq.com", user: bot, password: "*****")
      let mail = Mail(
              text: "",
              from: bot,
              to: to,
              cc: cc, // Addresses will be parsed for you
              subject: "title",
              attachments: [attachement]
      )
    
    opened by CodeEagle 3
  • Not working on all SMTP servers

    Not working on all SMTP servers

    My server return receivedBytes = 0

    public func recv(maxBytes: Int = BufferCapacity) throws -> [UInt8] {
            let data = Bytes(capacity: maxBytes)
            let flags: Int32 = 0 //FIXME: allow setting flags with a Swift enum
            let receivedBytes = socket_recv(self.descriptor, data.rawBytes, data.capacity, flags)
            guard receivedBytes > -1 else { throw SocksError(.readFailed) }
    
            my receivedBytes is 0 so it will execute the else block 
    
            guard receivedBytes > 0 else {
                // receiving 0 indicates a proper close     .. no error.
                // attempt a close, no failure possible because throw indicates already closed
                // if already closed, no issue. 
                // do NOT propogate as error
                _ = try? self.close()
                return []
            }
    
    

    After that

    In SMTPSocket.swift

     try sock.connect(servername: servername)
            let result = try sock.receive()
            // the result.count  is 0 so else block will be executed with error 'bad Request'
            guard result.count == 1 else {
                throw SMTP.SMTPError.badResponse
            }
    

    I have checked all the configuration and the server is running properly

    opened by wassimseif 2
  • Character encodings?

    Character encodings?

    Your usage examples have a text body that is plain ASCII. If one wants to send non-ASCII text, does Hedwig provide any assistance with MIME encoding and such?

    opened by jwwalker 0
  • Can't install pod using terminal

    Can't install pod using terminal

    How to install this framework through terminal? I get an error when use 'pod install'

    [!] CocoaPods could not find compatible versions for pod "Hedwig": In Podfile: Hedwig

    Specs satisfying the Hedwig dependency were found, but they required a higher minimum deployment target.

    opened by denikaev 0
  • smtp.163.com mail send failed

    smtp.163.com mail send failed

    error: Optional(bad response)

    i use mail.163.com server to send mail, but it does't work!. anyone else use Hedwig send maill to 163 server success? or any other maill server work?

    opened by ArmsZhou 0
  • Installation

    Installation

    How can i install this in my Project(Like cocoapods)..? I have installed but the error showing like this 'Cannot invoke initializer for type 'Hedwig' with an argument list of type '(hostName: String, user: String, password: String)'

    screen shot 2017-10-05 at 8 45 51 am
    opened by abdulmalikaman 4
  • Packaging trouble with Vapor 2

    Packaging trouble with Vapor 2

    You have an awesome mail tool. I used it successfully with Vapor 1 with no difficulties.

    I am upgrading to Vapor 2 and Hedwig has Vapor 1 dependencies and my vapor update get stuck.

    I suspect some dependency loop but there may be a catch to fixing it as it might cause similar problems to Vapor 1 users.

    I can fork and continue I suppose but you suggested opening an issue first.

    opened by steve-h 4
  • [Feature] Hedwing should skip invalidate email address rather than dispose all action

    [Feature] Hedwing should skip invalidate email address rather than dispose all action

    when you have one invalidate email address in you cc list, you fail all.

    [Hedwig] SMTP Error: bad response. bad response on command: RCPT TO: ****, response: Mailbox not found or access denied
    
    opened by CodeEagle 0
Releases(1.1.0)
Owner
Wei Wang
Developer, creator, proud father.
Wei Wang
Swift-cuckoo-collections - Cross-platform Swift dictionaries & sets that use a cuckoo hashing algorithm

CuckooCollections A Swift package for open-addressed sets and dictionaries that

Christopher Richez 0 Aug 2, 2022
Swift cross-platform crypto library using CommonCrypto/libcrypto

BlueCryptor Swift cross-platform crypto library derived from IDZSwiftCommonCrypto. IMPORTANT NOTE: This release is NOT entirely source code compatible

Kitura 183 Oct 15, 2022
Swift cross-platform crypto library using CommonCrypto/libcrypto

BlueCryptor Swift cross-platform crypto library derived from IDZSwiftCommonCrypto. IMPORTANT NOTE: This release is NOT entirely source code compatible

Kitura 183 Oct 15, 2022
To Practice UINavigationController, transition, ViewController Life Cycle, send data to different page, asset catalogs

LED Board Check Point ! StackView ์—ฌ๋Ÿฌ๊ฐœ์˜ view ๋ฅผ set ์œผ๋กœ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ์—ญํ™œ์„ ํ•จ ์ผ์ •ํ•œ ๊ทœ์น™์— ๋”ฐ๋ผ์„œ stack view ์•ˆ์— ์›€์ง์ด๋Š”๊ฒƒ์ž„ ์ด๋ฏธ์ง€ ๋„ฃ๊ธฐ ํ”„๋กœ์ ํŠธ ๋‚ด์— Assets ํด๋” ๋‚ด์— Image Set ์„ ์ถ”๊ฐ€ํ•˜์—ฌ 1x, 2x

Jacob Ko 0 Dec 5, 2021
Wi-attack: Cross-technology Impersonation Attack against iBeacon Services

Wi-attack: Cross-technology Impersonation Attack against iBeacon Services

Naxin 3 Nov 30, 2021
Oversecured Vulnerable iOS App is an iOS app that aggregates all the platform's known and popular security vulnerabilities.

Description Oversecured Vulnerable iOS App is an iOS app that aggregates all the platform's known and popular security vulnerabilities. List of vulner

Oversecured Inc 135 Dec 15, 2022
PassDrop is a fully-featured secure password management system, compatible with the free KeePass 1.x (Classic) and multi-platform KeePassX desktop applications.

passdrop This is a modern, updated build of Rudis Muiznieks's PassDrop application. PassDrop is a fully-featured secure password management system, co

Chad Austin 33 Sep 23, 2022
iOS library for device fingerprinting. Does not require server APIs to work, fully client-side operation.

Lightweight iOS library for local device fingerprinting Installation (CocoaPods) # Podfile pod 'FingerprintJS' Note: If you've never used CocoaPods fo

FingerprintJS 45 Dec 17, 2022
Virgil Core SDK allows developers to get up and running with Virgil Cards Service API quickly and add end-to-end security to their new or existing digital solutions to become HIPAA and GDPR compliant and more.

Virgil Core SDK Objective-C/Swift Introduction | SDK Features | Installation | Configure SDK | Usage Examples | Docs | Support Introduction Virgil Sec

Virgil Security, Inc. 27 Jul 26, 2022
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

Kitura 122 Dec 16, 2022
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

Kitura 122 Dec 16, 2022
Cloak Swift - a tool and Tuist plugin to encrypt secrets and then pass them in an obfuscated form into applications

This is Cloak Swift - a tool and Tuist plugin to encrypt secrets and then pass them in an obfuscated form into applications.

Andrew Lord 3 Nov 9, 2022
Safe and easy to use crypto for iOS and macOS

Swift-Sodium Swift-Sodium provides a safe and easy to use interface to perform common cryptographic operations on macOS, iOS, tvOS and watchOS. It lev

Frank Denis 483 Jan 5, 2023
Native and encrypted password manager for iOS and macOS.

Open Sesame Native and encrypted password manager for iOS and macOS. What is it? OpenSesame is a free and powerful password manager that lets you mana

OpenSesame 432 Jan 7, 2023
Simple, secure password and data management for individuals and teams

Padloc Simple, secure password and data management for individuals and teams (formerly known as Padlock). This repo is split into multiple packages: P

Padloc 2.1k Jan 8, 2023
PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. PGPro is made in Switzerland.

PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. P

Luca Nรคf 250 Jan 4, 2023
A wrapper to make it really easy to deal with iOS, macOS, watchOS and Linux Keychain and store your user's credentials securely.

A wrapper (written only in Swift) to make it really easy to deal with iOS, macOS, watchOS and Linux Keychain and store your user's credentials securely.

Ezequiel Aceto 2 Mar 29, 2022
CryptoSwift is a growing collection of standard and secure cryptographic algorithms implemented in Swift

CryptoSwift Crypto related functions and helpers for Swift implemented in Swift. (#PureSwift) Note: The master branch follows the latest currently rel

Marcin Krzyzanowski 9.4k Jan 5, 2023
A framework for the JOSE standards JWS, JWE, and JWK written in Swift.

JOSESwift is a modular and extensible framework for the JOSE standards JWS, JWE, and JWK written in Swift. ?? Please note that this implementation of

Airside Mobile, Inc. 162 Dec 15, 2022