Giter Club home page Giter Club logo

swift-smtp's Introduction

SwiftSMTP

SwiftSMTP provides a SwiftNIO based implementation for sending emails using SMTP servers.

There is the Configuration struct (and its nested structs and enums) that configure the access to a SMTP server (hostname, credentials, ...).

Once you have a Configuration (together with an NIO EventLoopGroup), you can create a Mailer. The mailer is responsible for setting up the NIO channel that connects to the SMTP server and delivers the email.

With a Mailer at your disposal, you can use it to send an Email. Since SMTP terminates the connection after each delivery, Mailer will create a new connection per Email that is to be delivered.

To use SwiftSMTP, add the following package dependency:

.package(url: "https://github.com/sersoft-gmbh/swift-smtp.git", from: "2.0.0")

Usage

The package contains two targets SwiftSMTP and SwiftSMTPVapor. The former is a pure SwiftNIO implementation, while the latter contains some helpers for using SwiftSMTP in Vapor (4) applications.

SwiftSMTP

To send an email in SwiftSMTP, first create a Configuration. The configuration contains the server parameters (server address, port, credentials, ...). Next you can create a Mailer with it. You'll also need a SwiftNIO EventLoopGroup (e.g. MultiThreadedEventLoopGroup). You then create an Email and simply call send(email:) on your mailer with it. The returned EventLoopFuture will return once the email was successfully sent, or will fail with the error returned from the SMTP server.

Creating a Configuration

There are multiple ways to create a configuration. The simplest is to use environment variables:

let configuration = Configuration.fromEnvironment()

The following environment variables are read (for more details please also check the header docs):

  • SMTP_HOST: The hostname to use or 127.0.0.1 if none is set.
  • SMTP_PORT: The port to use. The encryption's default will be used if not set or not a valid integer.
  • SMTP_ENCRYPTION: The encyrption to use.
  • SMTP_TIMEOUT: The connection time out in seconds. If not set or not a valid 64-bit integer, a sensible default.
  • SMTP_USERNAME: The username to use.
  • SMTP_PASSWORD: The password to use.
  • SMTP_USE_ESMTP: If set to 1, ESMTP will be used (e.g. send EHLO instead of just HELO).

You can also create a configuration partially from the environment. Each sub-object of Configuration has it's own .fromEnvironment() method. Of course you can also create the configuration completely without any environment values.

SwiftSMTPVapor

SwiftSMTPVapor builds on SwiftSMTP and adds some convenience for using it with Vapor. First, you need to configure SwiftSMTPVapor once at startup. This is usually done in configure(_:). There are multiple ways to configure SwiftSMTP here. The simplest is to use environment variables (see above for details on that):

/// Initialize SwiftSMTP
app.swiftSMTP.initialize(with: .fromEnvironment())

Another way to initialize SwiftSMTP is to use the SMTPInitializer lifecycle handler:

/// Initialize SwiftSMTP
app.lifecycle.use(SMTPInitializer(configuration: .fromEnvironment()))

The main difference between the two is that with the former, SwiftSMTP is ready to use after the call. The latter will initialize SwiftSMTP during the boot of the Vapor Application. In most cases, this difference doesn't matter and the two are equivalent.

You can of course also provide your own configuration. There are also additional parameters for specifiying the source of the event loop group to use for mailers, the maximum connections for mailers and whether or not to write transmission logs. Usually, those can be left to their defaults.

Next, you can use SwiftSMTP inside a request:

func handleRequest(_ request: Request) -> EventLoopFuture<Response> {
    let email: Email // created before
    return request.swiftSMTP.mailer.send(email: email).transform(to: Response())
}

This uses the shared mailer, which is lazily initialized. If you need a dedicated mailer, you can use the createNewMailer method:

func handleRequest(_ request: Request) -> EventLoopFuture<Response> {
    let email: Email // created before
    return request.swiftSMTP.createNewMailer().send(email: email).transform(to: Response())
}

When using the application's event loop group (which is the default), there will be almost no difference between the two - except maybe for the connection limit. A mailer has a connection limit of two connections by default, which means that a new mailer does not have any connections in its queue. When using a custom event loop group source, however, creating a new mailer will also create a new event loop group. It's important to keep this in mind, since you're responsible for shutting down that event loop group - whereas SwiftSMTPVapor takes care of shutting down the event loop group of the shared mailer if you use a custom source there.

SwiftSMTP also works with Swift concurrency:

func handleRequest(_ request: Request) async throws -> Response {
    let email: Email // created before
    try await request.swiftSMTP.mailer.send(email: email)
    return Response()
}

swift-smtp's People

Contributors

dependabot[bot] avatar ffried 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

swift-smtp's Issues

Implement further transmission options of email contents

Certain servers have problems if the lines get too long. #6 describes a case where the server simply truncates the lines and thus the email appears blank when delivered.

This could be resolved by adding further transmission options. The following options come to mind:

  • base64-only option with the ability to specify the maximum line length
  • a line-limit option which manually inserts CRLF's after a given line length

How to use with Queue. Can mailer be made public?

        @inlinable
        public
        func mailer(for eventLoop: EventLoop) -> Mailer {
            storage.mailers[ObjectIdentifier(eventLoop)]!
        }

EmailJob

context.application.swiftSMTP.mailer(for: context.eventLoop).send(email: realEmail)

HTML content being cutoff. Suspected base64 encoding issue

I encountered this previously with another dependancy (https://github.com/Kitura/Swift-SMTP), which was fixed with this commit: Kitura/Swift-SMTP@697e73a

Some SMTP servers will truncate lines that are too long - including major corporate Oracle servers. The result, is that emails are seemingly just blank when they are received.

I've tried to fix this by using options: .lineLength76Characters, but am still encountering this issue.

Unfortunately, I'm gonna have to revert everything back to the Kitura dependancy for now ๐Ÿ˜”

Document Example With Vapor 4

Hello,

I've been trying to implement this package in a Vapor 4 app without success. I believe I am correctly important the packages and are able to create Configuration structs. From what I see in the code, the framework creates its own EventLoopGroup, and creates a default mailer.

For the life of me I can't seem to get this to initialize properly. Clearly I am missing something that is the most obvious.

Could you provide a example of how you implement in Vapor. How to initialize in Configure.swift. (if that is appropriate). I'm pretty sure once initialized I can get it to work, but if you can have a simple example in a route where a mail is sent (similar to the CLI example) this would be so great.

Thanks again.

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.