Skip to content

coenttb/swift-emailaddress-type

swift-emailaddress-type

CI Development Status

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

Overview

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.

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

Installation

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/coenttb/swift-emailaddress-type", from: "0.0.1")
]

Quick Start

Basic Email Addresses

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 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 "john.doe@example.com".asEmailAddress()

// Convert to string
let emailString = email.stringValue
let addressOnly = email.addressValue  // 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

A Swift package with a type-safe EmailAddress model.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors 2

  •  
  •  

Languages