Type-safe email address validation and parsing for Swift, supporting multiple RFC standards.
swift-emailaddress-type provides a robust EmailAddress type that supports multiple RFC standards for email address formats:
- RFC 5321: SMTP email addresses (ASCII-only, strict format)
- RFC 5322: Internet Message Format addresses (ASCII with display names)
- RFC 6531: Internationalized email addresses (Unicode support)
The library automatically selects the most appropriate RFC format based on the input, while maintaining compatibility across all three standards.
- Multi-RFC Support: Seamlessly handles RFC 5321, 5322, and 6531 formats
- Internationalization: Full support for Unicode email addresses (RFC 6531)
- Display Names: Parse and format email addresses with display names
- Type Safety: Compile-time guarantees with Swift 6.0 strict concurrency
- Validation: Automatic validation against RFC standards
- Codable: Full JSON encoding/decoding support
- Domain Support: Integrated with
swift-domain-typefor proper domain handling
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/coenttb/swift-emailaddress-type", from: "0.0.1")
]import EmailAddress
// Simple email address
let email = try EmailAddress("john.doe@example.com")
print(email.address) // "john.doe@example.com"
print(email.localPart) // "john.doe"
print(email.domain.name) // "example.com"// Email with display name
let namedEmail = try EmailAddress("John Doe <john.doe@example.com>")
print(namedEmail.name) // "John Doe"
print(namedEmail.address) // "john.doe@example.com"
// Display name with special characters
let quotedEmail = try EmailAddress("\"Doe, John\" <john.doe@example.com>")
print(quotedEmail.name) // "Doe, John"// Initialize with explicit display name
let email1 = try EmailAddress(
displayName: "John Doe",
"john.doe@example.com"
)
// Initialize with local part and domain
let email2 = try EmailAddress(
localPart: "john.doe",
domain: "example.com"
)// Validate email format
do {
let email = try EmailAddress("john.doe@example.com")
print("Valid email: \(email)")
} catch {
print("Invalid email format")
}// Parse email with display name
let email = try EmailAddress("John Doe <john.doe@example.com>")
print(email.name) // Optional("John Doe")
print(email.address) // "john.doe@example.com"
print(email.stringValue) // "John Doe <john.doe@example.com>"// Email with special characters in local part
let specialEmail = try EmailAddress(
localPart: "test.!#$%&'*+-/=?^_`{|}~",
domain: "example.com"
)
// Quoted local part
let quotedLocal = try EmailAddress(
localPart: "\"john.doe\"",
domain: "example.com"
)// Email with subdomain
let email = try EmailAddress("test@sub1.sub2.example.com")
print(email.domain.name) // "sub1.sub2.example.com"let email = try EmailAddress("john.doe@example.com")
// Check if ASCII-only
print(email.isASCII) // true
print(email.isInternationalized) // false
// Access RFC-specific formats
if let rfc5321 = email.rfc5321 {
print("RFC 5321 format available")
}
if let rfc5322 = email.rfc5322 {
print("RFC 5322 format available")
}// Convert from string
let email = try "john.doe@example.com".asEmailAddress()
// Convert to string
let emailString = email.stringValue
let addressOnly = email.addressValue // Without display namestruct User: Codable {
let name: String
let email: EmailAddress
}
// Encoding
let user = User(
name: "John Doe",
email: try EmailAddress("john.doe@example.com")
)
let jsonData = try JSONEncoder().encode(user)
// Decoding
let decodedUser = try JSONDecoder().decode(User.self, from: jsonData)let email = try EmailAddress("john.doe@example.com")
// Get raw value
let rawValue = email.rawValue // "john.doe@example.com"
// Initialize from raw value
let reconstructed = EmailAddress(rawValue: rawValue)let email1 = try EmailAddress("John Doe <john@example.com>")
let email2 = try EmailAddress("john@example.com")
// Match addresses (ignores display name)
if email1.matches(email2) {
print("Same email address")
}let email = try EmailAddress("John Doe <john@example.com>")
// Normalize to most restrictive format
let normalized = email.normalized()// Enforce ASCII-only email
let asciiEmail = try EmailAddress.ascii("john@example.com")
// This would throw an error:
// let unicodeEmail = try EmailAddress.ascii("用户@example.com")The EmailAddress struct maintains representations in all three RFC formats when possible:
public struct EmailAddress: Hashable, Sendable {
let rfc5321: RFC_5321.EmailAddress? // SMTP format (ASCII-only)
let rfc5322: RFC_5322.EmailAddress? // Message format (ASCII with names)
let rfc6531: RFC_6531.EmailAddress // International format (Unicode)
public let displayName: String?
public var name: String?
public var address: String
public var localPart: String
public var domain: Domain
}- RFC 5321: Strict SMTP format, ASCII-only, no display names in address
- RFC 5322: Internet Message Format, supports display names and comments
- RFC 6531: Internationalized email, supports Unicode characters
The library automatically determines which RFC formats are compatible with a given email address and maintains all compatible representations.
public enum EmailAddressError: Error, Equatable, LocalizedError {
case conversionFailure
case invalidFormat(description: String)
}Hashable: Use in sets and as dictionary keysSendable: Safe for concurrent access (Swift 6.0)Codable: JSON encoding/decodingRawRepresentable: String conversionCustomStringConvertible: Readable output
- swift-domain-type: A Swift package with a type-safe Domain model.
- swift-authenticating: A Swift package for type-safe HTTP authentication with URL routing integration.
- swift-types-foundation: A Swift package bundling essential type-safe packages for domain modeling.
- swift-web-foundation: A Swift package with tools to simplify web development.
- Swift 6.0+
- macOS 13+ / iOS 16+
This project is licensed under the Apache 2.0 License. See LICENSE for details.
Contributions are welcome! Please feel free to submit a Pull Request.
This package is part of the coenttb suite of Swift server-side packages.
For issues, questions, or contributions, please visit the GitHub repository.