Postal is a swift framework providing simple access to common email providers.

Overview

Build Status Carthage Pods Swift 5.0 Platforms

Postal is a swift framework providing simple access to common email providers.

Example

Connect

let postal = Postal(configuration: .icloud(login: "[email protected]", password: "mypassword"))
postal.connect { result in
    switch result {
    case .success:
        print("success")
    case .failure(let error):
        print("error: \(error)")
    }
}

Search

let filter = .subject(value: "Foobar") && .from(value: "[email protected]")
postal.search("INBOX", filter: filter) { result in
    switch result {
    case .success(let indexes):
        print("success: \(indexes)")
    case .failure(let error):
        print("error: \(error)")
    }
}

Fetch

let indexset = NSIndexSet(index: 42)
postal.fetchMessages("INBOX", uids: indexset, flags: [ .headers ], onMessage: { email in
    print("new email received: \(email)")
}, onComplete: error in
    if error = error {
        print("an error occured: \(error)")
    }
}

Want to debug your IMAP session ?

postal.logger = { log in
    print(log)
}

What about Mailcore ?

Postal does not address the same goal as MailCore. You can take a look at our thoughts in the TechnicalNotes document.

Provider quirks

Email protocol is standardized. However providers implementations often provides extension or variations of these standards. We tried to build a document to synthesize working around these variations here: ProviderQuirks.

Contributing

Postal has been a great effort and we could really use your help on many areas:

  • Finding and reporting bugs.
  • New feature suggestions.
  • Answering questions on issues.
  • Documentation improvements.
  • Reviewing pull requests.
  • Fixing bugs/new features.
  • Improving tests.
  • Contribute to elaborate the Roadmap.

If any of that sounds cool to you, please send a pull request!

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms that you can find here: CodeOfConduct.

Requirements

  • Xcode 10
  • OS X 10.10 or later
  • iOS 8.0 or later

Installation

Carthage

Postal is Carthage compatible.

  • Add github "snipsco/Postal" to your Cartfile.
  • Run carthage update.

CocoaPods

Postal also can be used by CocoaPods.

  • Add the followings to your Podfile:
use_frameworks!
pod 'Postal'
  • Run pod install.

Manual

  1. Add the Postal repository as a submodule of your application’s repository.
git submodule add https://github.com/snipsco/Postal.git
git submodule update --init --recursive
  1. Drag and drop Postal.xcodeproj into your application’s Xcode project or workspace.
  2. On the “General” tab of your application target’s settings, add Postal.framework to the “Embedded Binaries” section.
  3. If your application target does not contain Swift code at all, you should also set the EMBEDDED_CONTENT_CONTAINS_SWIFT build setting to “Yes”.

License

Postal is released under the MIT License.

Comments
  • fetchLast and fetchMessages never return...

    fetchLast and fetchMessages never return...

    I try to access my IMAP server with this code, which is based on your demo code:

    `

    import Foundation
    import Postal
    
    class MailManagerPostal {
        var configuration: Configuration!
        
        fileprivate lazy var postal: Postal = Postal(configuration: self.configuration)
        fileprivate var messages: [FetchResult] = []
        
        init(hostname: String, userName: String, password: String) {
            log.debug("init called...")
            
            configuration = Configuration(hostname: hostname, port: 993, login: userName, password: .plain(password), connectionType: .tls, checkCertificateEnabled: false)
    
            log.debug("configuration created: \(self.configuration.description)")
            
            postal.connect(timeout: Postal.defaultTimeout, completion: { [weak self] result in
                log.debug("postal.connect completed.")
                switch result {
                case .success:
                    log.debug("fetching messages now.")
                    
                    let indexset = IndexSet(0...100000)
                    
                    self?.postal.fetchMessages("INBOX", uids: indexset, flags: [ .fullHeaders ], onMessage: { message in
                        log.debug("message : \(message.header)")
                        self?.messages.insert(message, at: 0)
                    }, onComplete: { error in
                        if let error = error {
                            log.error("fetch failed: \((error as NSError).localizedDescription)")
                        } else {
                            log.debug("connection successful")
                        }
                        log.debug("fetch complete.")
                    })
                    
                case .failure(let error):
                    log.error("connection failed: \((error as NSError).localizedDescription)")
                }
            })
            log.debug("init finished.")
        }
    }
    

    `

    Problem: The last message I see is "fetching messages now.". Then nothing happens any more. What's happening here? Where is my mistake? The credentials I use work with using mailcode2 without a problem.

    Some more questions:

    • How can I debug the IMAP requests?
    • Where can I find a documentation of the API?
    • Can I manipulate message, especially add custom headers to a message (or take a message, add custom headers, write it as a new message to the server and delete the old one...)?
    opened by ikemuc 8
  • fetchMessages attempts to fetch 1 additional message (fetchLast fails with .undefined)

    fetchMessages attempts to fetch 1 additional message (fetchLast fails with .undefined)

    It appears that giving an IndexSet to fetchMessages() with a single index actually tries to fetch 2 messages. This also means that fetchLast() fails.

    i.e.

       let indexset = IndexSet(integer: 2750)
       postal.fetchMessages("INBOX", uids: indexset, flags: [ .fullHeaders ], ...
    

    actually tries to fetch messages 2750 and 2751.

    opened by matadan 6
  • Question: How do you get the message text?

    Question: How do you get the message text?

    I'm struggling to find the right API to use to retrieve the message body. If I take the raw data from a message part, I can convert it to a String but it has extraneous characters. Is there an API to use to get the contents of a message?

    question 
    opened by matadan 3
  • Clean up from Xcode 10.2 changes

    Clean up from Xcode 10.2 changes

    As mentioned in the recent XCode 10.2 PR thread: https://github.com/snipsco/Postal/pull/83#issuecomment-485564820

    • Result module was removed but is still referenced in Postal.podspec. I don't use pods in my project so I'm not sure what issues this may cause.

    • Postal-iOS framework has 7 swift language-related warnings:

    Screen Shot 2019-04-22 at 5 39 00 PM
    opened by ktkopone 2
  • "Use of extraneous '&'" error when building for iOS 12

    When compiling a project with Postal installed via CocoaPods, the build fails in Extensions+Parsing.swift with error Use of extraneous '&' in lines 51, 55, 60 and 64

    opened by henrik-dmg 2
  • Circle CI can't find libetpan

    Circle CI can't find libetpan

    Breaks here

    ❌  /Users/distiller/theios/Pods/Postal/dependencies/module.modulemap:2:12: header 'build/ios/include/libetpan/libetpan.h' not found
    
        header "build/ios/include/libetpan/libetpan.h"
               ^
    
    
    
    ❌  /Users/distiller/theios/Pods/Postal/Postal/Address+Parsing.swift:26:8: could not build Objective-C module 'libetpan'
    
    import libetpan
           ^
    

    Any ideas how to fix, it works locally.

    opened by dai-cb 2
  • Compatibility with ReactiveCocoa 6.0.0 / ReactiveSwift 2.0.0

    Compatibility with ReactiveCocoa 6.0.0 / ReactiveSwift 2.0.0

    Hi,

    I'd like to use ReactiveCocoa 6.0.0 (using ReactiveSwift 2.0.0) in my application, but found out (by a dependency problem with Result 3.1 vs. 3.2), that Postal uses ReactiveSwift 1.

    Is there any chance, that Postal works with ReactiveSwift 2 / ReactiveCocoa 6 / Result 3.2.3 ?

    Regards, Eike

    opened by ikemuc 2
  • Optimization of NSIndexSet.enumerate(batchSize: Int)

    Optimization of NSIndexSet.enumerate(batchSize: Int)

    Problem: We have to optimize the NSIndexSet.enumerate(batchSize: Int) because of too much complexity in it -> O(n)

    Example: If we try to fetch all emails we would do something like:

    let range = NSRange(location: 1, length: Int.max - 1)
    let indexSet = NSIndexSet(indexesInRange: range)
    
    var results = [FetchResult]()
    try imapSession.fetchMessages("INBOX", set: IMAPIndexes.indexes(indexSet), flags: [ .fullHeaders ]) { _ in }
    

    Current result: It takes too much time for a provider that have a batchSize == Int.max to create the only one indexset needed for the fetch.

    Expected result: Instant fetch

    Possible solution: We could try to use the Strideable protocol instead or simply optimize inside the method.

    bug 
    opened by klefevre 2
  • What is the API to get the text content of an email?

    What is the API to get the text content of an email?

    It was asked here by someone: https://stackoverflow.com/questions/41155748/how-get-mail-content-using-postal-swift-framework

    Please let me know if there are any document or dev guide to start? Or how to find out?

    opened by tlkahn 1
  • postal.logger statement doesn't compile

    postal.logger statement doesn't compile

    Hi klevefre,

    you wrote about debugging Postal:

    You can set a closure on a Postal instance to have IMAP logs: let postal = Postal(configuration: ...) postal.logger { log in print(log) }

    Unfortunately this doesn't work in my code. I get the compiler error message "Cannot call value of non-function type 'logger?'

    This is my code:

    init(hostname: String, userName: String, password: String) {
        log.debug("init called...")
        
        configuration = Configuration(hostname: hostname, port: 993, login: userName, password: .plain(password), connectionType: .tls, checkCertificateEnabled: false)
        
        let postal: Postal = Postal(configuration: configuration)
        postal.logger { log in
            print(log)
        }
    [...]
    

    What's wrong with my code? It's exactly as you wrote...?

    opened by ikemuc 1
  • How know encode type when I parse content a mail?

    How know encode type when I parse content a mail?

    I have created a mail app using Postal Framework and my mail server send the message to app with different type data, so how I know a data in body is encode/decode by type? In my example I don't know data should encode with NSUTF8StringEncoding or NSISO2022JPStringEncoding :(

    msg.body?.allParts.forEach({ (singlePart) in
        let meesage = String.init(data: (singlePart.data?.rawData)!, encoding: NSUnicodeStringEncoding)
        if singlePart.mimeType == MimeType.textPlain {
            mailInfo.messageDescription = meesage?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) ?? ""
        } else if singlePart.mimeType == MimeType.textHtml {
            mailInfo.message = meesage ?? ""
        }
    })
    

    Thanks for support!

    opened by khacdai37 1
  • Further development?

    Further development?

    Postal looks fantastic, and the approach of interfacing with libetpan directly is the way to go. However I'm saddened to see there's been no activity since 2017 - is this project still supported by its creators? MailCore stopped working recently and I'm saddened to see another great effort has stopped as well.

    opened by guidedways 4
  • Is support for push (IDLE) planned?

    Is support for push (IDLE) planned?

    I was wondering if Postal supports Push (i.e. the user's email server informing an app that uses Postal about new messages). As far as I understand, this is known under the name IDLE (https://tools.ietf.org/html/rfc2177).

    I didn't find any traces of it in the examples or in documentation/roadmap, so I thought I would ask how big the interest is in implementing it or if there have been any plans already.

    I have also checked libetpan and it seems like it's available there. If implementing it is (in your opinion) uncomplicated enough for me to try it without substantial C experience, I'd love a tip on where to start.

    Otherwise, I would greatly appreciate any advice on what other packages I might use for that functionality in a macOS app. I'm writing it in Swift, but wouldn't mind using a package from another language, if the interop works. From what I found, MailCore or libetpan could be my only options, would be interested to find out otherwise.

    Thanks for any advice/help and to the contributors for their work.

    opened by janek 0
  • Certificate error

    Certificate error

    Whenever I try to connect to any e-mail account, I am getting a certificate error.

    error: certificate. The operation couldn’t be completed. (Postal.PostalError error 4.)

    opened by cemiltokatli 0
  • Commandline App | Postal library | postal.connect | I get nothing back (no error or else)

    Commandline App | Postal library | postal.connect | I get nothing back (no error or else)

    Hello,

    I am new in this library and I hope I get help here. I use Swift 5.

    When I use the following code I get only "ENDED" but nothing else back in the console. No error message. What I am doing wrong?

    A happy New Year to all.

    Greetings, Sven

    import Foundation      
    import Postal  
        
    let postal : Postal = Postal(configuration: Configuration(hostname: "email.none.none", port: 993, login: "[email protected]", password: .plain("test"), connectionType: .tls, checkCertificateEnabled: true, batchSize: 1000, spamFolderName: "junk"))  
        
    func getEmail() {  
        let indexset = IndexSet(integer: 1)  
        postal.fetchMessages("INBOX", uids: indexset, flags: [ .headers ], onMessage: { email in  
            print("new email received: \(email)")  
        }, onComplete: { error in  
            if error == error {  
                print("an error occured: \(error)")  
            }  
        })  
    }  
        
    postal.connect { result in  
        switch result {  
        case .success:  
            getEmail()  
        case .failure(let error):  
            print("error: \(error)")  
        }  
    }  
        
    print("ENDED")  
    
    opened by sm-a 0
Releases(v0.5.0)
Owner
Snips
We make technology disappear
Snips
Cordova Email Plugin

Forked to fix Android 11 problems – No future support! SAMPLE APP ?? Cordova Email Plugin The plugin provides access to the standard interface that ma

null 0 Oct 22, 2021
SwiftyEmail - A super simple Swift e-mail composer package

SwiftyEmail is a mini library for iOS, iPadOS and Mac Catalyst using MessageUI. With SwiftyEmail, you'll be able to send e-mails from your app calling your user's favorite e-mail app (including third party ones!).

Marcos Morais 5 Nov 20, 2022
MailCore 2 provide a simple and asynchronous API to work with e-mail protocols IMAP, POP and SMTP.

MailCore 2: Introduction MailCore 2 provides a simple and asynchronous Objective-C API to work with the e-mail protocols IMAP, POP and SMTP. The API h

MailCore 2.5k Jan 1, 2023
PJFDataSource is a small library that provides a simple, clean architecture for your app to manage its data sources while providing a consistent user interface for common content states (i.e. loading, loaded, empty, and error).

PJFDataSource PJFDataSource is a small library that provides a simple, clean architecture for your app to manage its data sources while providing a co

Square 88 Jun 30, 2022
Commands providing shortcuts to common Postgres introspection queries (Swift port of heroku-pg-extras)

Commands providing shortcuts to common Postgres introspection queries (Swift port of heroku-pg-extras)

Sven A. Schmidt 2 May 27, 2022
A validator for postal codes with support for 200+ regions

PostalCodeValidator A validator for postal codes with support for 200+ regions. import Foundation import PostalCodeValidator if let validator = Posta

FormatterKit 211 Jun 17, 2022
A simple OAuth library for iOS with a built-in set of providers

SwiftyOAuth is a small OAuth library with a built-in set of providers and a nice API to add your owns. let instagram: Provider = .instagram(clientID:

Damien 477 Oct 15, 2022
A simple OAuth library for iOS with a built-in set of providers

SwiftyOAuth is a small OAuth library with a built-in set of providers and a nice API to add your owns. let instagram: Provider = .instagram(clientID:

Damien 477 Oct 15, 2022
News application with 66 providers

News Description An application that let's you discover and read news. It's possible with using News API, that provides simple and easy-to-use API tha

Ivan Magda 18 Dec 10, 2022
SwiftMath is a Swift framework providing some useful math constructs and functions

SwiftMath is a Swift framework providing some useful math constructs and functions, like complex numbers, vectors, matrices, quaternions, and polynomials.

Matteo Battaglio 175 Dec 2, 2022
Matrix-rust-components-swift - Swift package providing components from the matrix-rust-sdk

Swift package for Matrix Rust components This repository is a Swift Package for

matrix.org 10 Nov 4, 2022
The XCTest Project, A Swift core library for providing unit test support

XCTest The XCTest library is designed to provide a common framework for writing unit tests in Swift, for Swift packages and applications. This version

Apple 1k Jan 4, 2023
SamuraiTransition is an open source Swift based library providing a collection of ViewController transitions featuring a number of neat “cutting” animations.

SamuraiTransiton is a ViewController transition framework in Swift. It is an animation as if Samurai cut out the screen with a sword. transition types

hachinobu 273 Dec 29, 2022
RadialMenu is a custom control for providing a touch context menu (like iMessage recording in iOS 8) built with Swift & POP

RadialMenu Looking for help? For $150/hr I'll help with your RadialMenu problems including integrating it into your project. Email [email protected] t

Brad Jasper 297 Nov 27, 2022
Email Validation Example With Swift

EmailValidation Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installation Em

null 1 Dec 4, 2021
SamuraiTransition is an open source Swift based library providing a collection of ViewController transitions featuring a number of neat “cutting” animations.

SamuraiTransiton is a ViewController transition framework in Swift. It is an animation as if Samurai cut out the screen with a sword. transition types

hachinobu 273 Dec 29, 2022
SwiftEmailValidator - A Swift implementation of an international email address syntax validator based on RFC5321 & RFC5322

SwiftEmailValidator A Swift implementation of an international email address syn

Dave Poirier 21 Oct 24, 2022
Swift µframework providing Future

Future [] (https://github.com/Carthage/Carthage) Swift µframework providing Future<T, Error>. This library is inspired by the talk of Javier Soto at S

Le Van Nghia 122 Jun 3, 2021
Send email to any SMTP server like a boss, in Swift and cross-platform

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 ema

Wei Wang 1.1k Jan 3, 2023
ProtonMail for macOS - Experimental email client for the ProtonMail service written in Swift

ProtonMail for macOS Experimental email client for the ProtonMail service written in Swift. About A pet project, largely incomplete and missing major

Marcel Piestansky 33 Jan 2, 2023