Files
ccn/Packages/Utility/Sources/Public/Methods/NormalizeEmail.swift
T
2026-08-19 23:19:08 +02:00

50 lines
1.6 KiB
Swift

import Foundation
/// A validator reducing a submitted email address to its canonical form.
///
/// Trims surrounding whitespace, lowercases the address (so one mailbox cannot register once per spelling), caps it at the 254 bytes an address can
/// be, and checks its shape: something before the `@`, and a domain with a dot. Control characters are rejected separately: the shape only excludes
/// whitespace, which would let non-whitespace controls (such as `NUL`) into the stored address.
public struct NormalizeEmail: Sendable {
// MARK: Initializers
/// Creates an email normalization method.
public init() {}
// MARK: Functions
/// Validates and normalizes a submitted email address.
/// - Parameter email: the submitted email address, if any.
/// - Returns: the normalized address, or `nil` when the submission is missing or invalid.
public func callAsFunction(
_ email: String?
) -> String? {
guard
let email = email?
.trimmingCharacters(in: .whitespacesAndNewlines)
.lowercased(),
email.utf8.count <= Constant.Length.maxEmail,
!email.unicodeScalars.contains(where: {
$0.properties.generalCategory == .control
}),
email.wholeMatch(of: /[^\s@]+@[^\s@]+\.[^\s@]+/) != nil
else {
return nil
}
return email
}
}
// MARK: - Constants
private enum Constant {
/// A namespace for the length constants.
enum Length {
/// The longest an email address can be, in bytes, per RFC 5321's path limit.
static let maxEmail = 254
}
}