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.
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.
- 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
- 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
- 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)
- 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 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
- 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
- Swift 5.9+
- macOS 11.0+ / iOS 14.0+ / tvOS 14.0+ / watchOS 7.0+ / Linux
| 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 | ✅ | ✅ | ✅ |
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"
]
)
]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()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// 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)")
}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 = signedif 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)")
}
}let signer = try DkimSigner(
domain: "example.com",
selector: "selector1",
privateKey: privateKeyPEM,
algorithm: .rsaSha256
)
try signer.sign(message)let verifier = DkimVerifier()
let results = try await verifier.verify(message)
for result in results {
print("Domain: \(result.domain)")
print("Status: \(result.status)")
}@_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")
}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 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.
CRL and OCSP revocation checking is not yet supported. The underlying swift-certificates library does not currently provide CRL/OCSP support.
Comprehensive documentation is available at migueldeicaza.github.io/MimeFoundation.
Getting Started
Creating and Parsing Messages
Working with Content
Security and Cryptography
- S/MIME Overview
- Signing Messages
- Encrypting Messages
- Verifying Signatures
- Certificate Management
- DKIM Signing
Advanced Topics
swift package plugin --allow-writing-to-directory ./docs generate-documentation \
--target MimeFoundation \
--output-path ./docs \
--transform-for-static-hostingexport MIME_BENCHMARKS=1
swift package benchmarkMimeFoundation is available under the MIT License. See the LICENSE file for details.
