Skip to content

swift-emailaddress-standard

Development Status CI

Type-safe email address validation and parsing for Swift, supporting multiple RFC standards.

Overview

swift-emailaddress-standard 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.

Features

  • 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-standard for proper domain handling

Installation

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/swift-standards/swift-emailaddress-standard", from: "0.4.3")
]

Add the product to your target:

.target(
    name: "App",
    dependencies: [
        .product(name: "EmailAddress Standard", package: "swift-emailaddress-standard")
    ]
)

Quick Start

Basic Email Addresses

import EmailAddress_Standard

// 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 Addresses with Display Names

// 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"

Component-Based Initialization

// 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"
)

Usage Examples

Email Validation

// Validate email format
do {
    let email = try EmailAddress("john.doe@example.com")
    print("Valid email: \(email)")
} catch {
    print("Invalid email format")
}

Working with Display Names

// 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>"

Special Characters and Quoted Local Parts

// 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"
)

Subdomains

// Email with subdomain
let email = try EmailAddress("test@sub1.sub2.example.com")
print(email.domain.name) // "sub1.sub2.example.com"

RFC Format Detection

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")
}

String Conversion

// Convert from string
let email = try EmailAddress("john.doe@example.com")

// Convert to string
let emailString = email.value
let addressOnly = email.address  // Without display name

Codable Support

struct 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)

RawRepresentable

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)

Email Matching

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")
}

Normalization

let email = try EmailAddress("John Doe <john@example.com>")

// Normalize to most restrictive format
let normalized = email.normalized()

ASCII-Only Emails

// Enforce ASCII-only email
let asciiEmail = try EmailAddress.ascii("john@example.com")

// This would throw an error:
// let unicodeEmail = try EmailAddress.ascii("用户@example.com")

Architecture

EmailAddress Type

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 Standards

  • 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.

Error Handling

public enum EmailAddressError: Error, Equatable, LocalizedError {
    case conversionFailure
    case invalidFormat(description: String)
}

Protocol Conformances

  • Hashable: Use in sets and as dictionary keys
  • Sendable: Safe for concurrent access (Swift 6.0)
  • Codable: JSON encoding/decoding
  • RawRepresentable: String conversion
  • CustomStringConvertible: Readable output

Related Packages

Dependencies

Used By

Requirements

  • Swift 6.0+
  • macOS 13+ / iOS 16+

License

This project is licensed under the Apache 2.0 License. See LICENSE for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Feedback

This package is part of the coenttb suite of Swift server-side packages.

For issues, questions, or contributions, please visit the GitHub repository.

About

RFC 5321, 5322, and 6531 email address validation and parsing for Swift.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Sponsor this project

Contributors

Languages