Skip to content

migueldeicaza/MimeFoundation

Repository files navigation

MimeFoundation

MimeFoundation Banner

MimeFoundation is a comprehensive Swift library for creating, parsing, and manipulating MIME messages. It provides everything you need to work with email messages, including S/MIME cryptographic security, DKIM signing/verification, and full internationalization support. You can use this together with MailFoundation.

Origin and Goal

This project is a port of the .NET Foundation mail stack originally created by Jeffrey Stedfast (MailKit/MimeKit. The goal is to bring those capabilities and API ergonomics to Swift developers, with modern async/await support and a Swift-native type system.

MimeFoundation pairs with MailFoundation to provide a complete mail solution—MimeFoundation handles MIME parsing and message construction while MailFoundation provides IMAP, POP3, and SMTP protocol implementations.

Features

Message Parsing and Creation

  • RFC 5322 Compliant: Full support for parsing and generating standards-compliant email messages
  • Stream-Based Processing: Efficient handling of large messages with minimal memory footprint
  • Async/Await Support: Modern Swift concurrency for non-blocking I/O operations
  • Mbox Support: Parse and iterate over Unix mbox files

MIME Content Handling

  • Multipart Messages: Create and parse multipart/mixed, multipart/alternative, multipart/related, etc.
  • Attachments: Easy attachment handling with automatic MIME type detection
  • Text Content: Support for plain text and HTML with automatic charset handling
  • Embedded Content: Handle inline images and related content in HTML messages
  • TNEF Support: Parse Microsoft TNEF (winmail.dat) attachments

Content Encodings

  • Transfer Encodings: Base64, Quoted-Printable, UUEncode, yEncode
  • Character Sets: Full Unicode support with automatic charset detection and conversion
  • Internationalized Headers: RFC 2047 encoded-word support for non-ASCII headers
  • IDN Support: Internationalized domain names (Punycode)

S/MIME Security

  • Digital Signatures: Sign messages with X.509 certificates (multipart/signed, application/pkcs7-mime)
  • Signature Verification: Verify S/MIME signatures and extract signer information
  • Encryption: Encrypt messages for recipients (macOS only, pending swift-certificates EnvelopedData)
  • Decryption: Decrypt S/MIME encrypted messages (macOS only)
  • Certificate Management: In-memory stores, SQLite databases with encrypted private keys, chain validation

DKIM and Email Authentication

  • DKIM Signing: Sign outgoing messages with DomainKeys Identified Mail
  • DKIM Verification: Verify DKIM signatures on incoming messages
  • ARC Support: Authenticated Received Chain verification
  • Authentication-Results: Parse and generate authentication result headers

Certificate Management

  • X509CertificateStore: Thread-safe in-memory certificate storage
  • SqliteCertificateDatabase: Persistent storage with AES-256-GCM encrypted private keys
  • Chain Validation: RFC 5280 compliant certificate chain validation
  • S/MIME Capabilities: Track recipient encryption algorithm preferences

Requirements

  • Swift 5.9+
  • macOS 11.0+ / iOS 14.0+ / tvOS 14.0+ / watchOS 7.0+ / Linux

Platform Feature Matrix

Feature macOS iOS/tvOS/watchOS Linux
MIME Parsing
Message Creation
S/MIME Signing
S/MIME Verification
S/MIME Encryption
S/MIME Decryption
DKIM Signing
DKIM Verification
Certificate Database

Installation (Swift Package Manager)

Add the package to your Package.swift dependencies:

dependencies: [
    .package(url: "https://github.com/migueldeicaza/MimeFoundation", branch: "main")
]

Then add MimeFoundation to your target dependencies:

targets: [
    .target(
        name: "YourApp",
        dependencies: [
            "MimeFoundation"
        ]
    )
]

Usage

Creating a Simple Message

import MimeFoundation

let message = MimeMessage()
message.from.add(MailboxAddress(name: "Alice", address: "alice@example.com"))
message.to.add(MailboxAddress(name: "Bob", address: "bob@example.com"))
message.subject = "Hello from MimeFoundation!"
message.body = TextPart("plain", "This is the message body.")

// Write to a stream or get as data
let data = try message.toData()

Creating a Message with Attachments

let message = MimeMessage()
message.from.add(MailboxAddress("sender@example.com"))
message.to.add(MailboxAddress("recipient@example.com"))
message.subject = "Document attached"

let multipart = Multipart("mixed")

// Add text body
multipart.add(TextPart("plain", "Please find the document attached."))

// Add attachment
let attachment = try MimePart.fromFile("/path/to/document.pdf")
attachment.contentDisposition = ContentDisposition(.attachment)
attachment.contentDisposition?.fileName = "document.pdf"
multipart.add(attachment)

message.body = multipart

Parsing Messages

// Parse from data
let message = try MimeMessage.load(data: messageData)

// Parse from file
let message = try MimeMessage.load(filePath: "/path/to/message.eml")

// Parse from stream (async)
let message = try await MimeMessage.loadAsync(stream: inputStream)

// Access message properties
print("From: \(message.from)")
print("Subject: \(message.subject ?? "(none)")")

// Get text content
if let textBody = message.textBody {
    print("Body: \(textBody)")
}

S/MIME Signing

import MimeFoundation

// Create a signer with your certificate and private key
let signer = try CmsSigner(
    certificatePEM: signingCertificate,
    privateKeyPEM: privateKey,
    digestAlgorithm: .sha256
)

// Sign the message body
let context = DefaultSecureMimeContext.shared
let signed = try MultipartSigned.create(
    message.body!,
    signer: signer,
    context: context
)

message.body = signed

S/MIME Verification

if let signed = message.body as? MultipartSigned {
    let context = DefaultSecureMimeContext.shared
    let signatures = try context.verify(signed)

    for signature in signatures {
        print("Signed by: \(signature.signer)")
        print("Valid: \(!signature.isExpired)")
    }
}

DKIM Signing

let signer = try DkimSigner(
    domain: "example.com",
    selector: "selector1",
    privateKey: privateKeyPEM,
    algorithm: .rsaSha256
)

try signer.sign(message)

DKIM Verification

let verifier = DkimVerifier()
let results = try await verifier.verify(message)

for result in results {
    print("Domain: \(result.domain)")
    print("Status: \(result.status)")
}

Certificate Database

@_spi(CMS) import X509

// Create a persistent certificate database
let db = try SqliteCertificateDatabase(
    path: "/path/to/certificates.db",
    password: "encryption-password"
)

// Add a certificate with private key
let record = X509CertificateRecord(
    certificate: cert,
    privateKey: key,
    isTrusted: true
)
try db.add(record)

// Find certificates for an email address
let certs = db.findCertificates(
    forEmail: "alice@example.com",
    now: Date(),
    requirePrivateKey: true
)

// Validate a certificate chain
let validator = X509ChainValidator()
let result = await validator.validate(leaf: userCert, database: db)
if result.isValid {
    print("Certificate chain is valid")
}

Known Limitations

S/MIME Encryption (iOS/Linux)

S/MIME encryption and decryption require Apple's Security framework (CMSEncoder/CMSDecoder) and are only available on macOS. Cross-platform support is pending the addition of EnvelopedData support in swift-certificates.

RSA Private Key Storage

RSA private keys cannot currently be round-tripped through the certificate database encryption due to format differences in swift-certificates' PEM serialization. EC keys (P-256, P-384, P-521) work correctly.

Certificate Revocation

CRL and OCSP revocation checking is not yet supported. The underlying swift-certificates library does not currently provide CRL/OCSP support.

Documentation

Comprehensive documentation is available at migueldeicaza.github.io/MimeFoundation.

Documentation Topics

Getting Started

Creating and Parsing Messages

Working with Content

Security and Cryptography

Advanced Topics

Generate Documentation Locally

swift package plugin --allow-writing-to-directory ./docs generate-documentation \
  --target MimeFoundation \
  --output-path ./docs \
  --transform-for-static-hosting

Running Benchmarks

export MIME_BENCHMARKS=1
swift package benchmark

License

MimeFoundation is available under the MIT License. See the LICENSE file for details.

About

Port of MimeKit to Swift

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages