Class EmailAddress
- Namespace
- FunctionalDdd
- Assembly
- FunctionalDdd.CommonValueObjects.dll
Represents an email address value object with RFC 5322-compliant validation. Ensures that email addresses are syntactically valid and prevents invalid email data in the domain model.
[JsonConverter(typeof(ParsableJsonConverter<EmailAddress>))]
public class EmailAddress : ScalarValueObject<string>, IComparable<ValueObject>, IEquatable<ValueObject>, IConvertible, IParsable<EmailAddress>
- Inheritance
-
EmailAddress
- Implements
- Inherited Members
- Extension Methods
Examples
Basic email address validation:
// Valid email addresses
var email1 = EmailAddress.TryCreate("user@example.com");
// Returns: Success(EmailAddress("user@example.com"))
var email2 = EmailAddress.TryCreate("john.doe+tag@company.co.uk");
// Returns: Success(EmailAddress("john.doe+tag@company.co.uk"))
// Invalid email addresses
var invalid1 = EmailAddress.TryCreate("not-an-email");
// Returns: Failure(ValidationError("Email address is not valid."))
var invalid2 = EmailAddress.TryCreate("@example.com");
// Returns: Failure(ValidationError("Email address is not valid."))
var invalid3 = EmailAddress.TryCreate(null);
// Returns: Failure(ValidationError("Email address is not valid."))
Using in domain entities:
public class User : Entity<UserId>
{
public EmailAddress Email { get; private set; }
public FirstName FirstName { get; }
private User(UserId id, EmailAddress email, FirstName firstName)
: base(id)
{
Email = email;
FirstName = firstName;
}
public static Result<User> Create(string email, string firstName) =>
EmailAddress.TryCreate(email)
.Combine(FirstName.TryCreate(firstName))
.Map((emailAddr, name) => new User(UserId.NewUnique(), emailAddr, name));
public Result<User> ChangeEmail(string newEmail) =>
EmailAddress.TryCreate(newEmail)
.Tap(email => Email = email)
.Map(_ => this);
}
Using with field name for validation errors:
// Specify field name for better error messages
var result = EmailAddress.TryCreate("invalid", "userEmail");
// Returns: Failure(ValidationError("Email address is not valid.", fieldName: "userEmail"))
// In API validation
public record RegisterUserRequest(string Email, string Password);
app.MapPost("/register", (RegisterUserRequest request) =>
EmailAddress.TryCreate(request.Email, nameof(request.Email))
.Bind(email => _authService.RegisterAsync(email, request.Password))
.ToHttpResult());
// Invalid email response:
// {
// "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
// "title": "One or more validation errors occurred.",
// "status": 400,
// "errors": {
// "email": ["Email address is not valid."]
// }
// }
Using IParsable for parsing scenarios:
// Standard .NET parsing pattern
var email = EmailAddress.Parse("user@example.com", null);
// Throws FormatException if invalid
// TryParse pattern
if (EmailAddress.TryParse("user@example.com", null, out var emailAddress))
{
Console.WriteLine($"Valid email: {emailAddress.Value}");
}
else
{
Console.WriteLine("Invalid email format");
}
JSON serialization in APIs:
public record UserDto(EmailAddress Email, string Name);
// Automatic JSON serialization/deserialization
var user = new UserDto(
EmailAddress.TryCreate("user@example.com").Value,
"John Doe"
);
// Serializes to:
// {
// "email": "user@example.com",
// "name": "John Doe"
// }
// Deserializes from JSON string to EmailAddress value object
Remarks
EmailAddress is a domain primitive that encapsulates email address validation and provides:
- RFC 5322 email format validation using a compiled regex
- Type safety preventing mixing of email addresses with other strings
- Immutability ensuring email addresses cannot be changed after creation
- IParsable implementation for .NET parsing conventions
- JSON serialization support for APIs and persistence
- Activity tracing for monitoring and diagnostics
Validation rules:
- Must not be null or empty
- Must contain an @ symbol separating local and domain parts
- Local part (before @): letters, digits, and special characters (!#$%&'*+/=?^_`{|}~-)
- Domain part (after @): letters, digits, hyphens, and dots with valid structure
- Case-insensitive validation (email is stored as provided, not normalized)
Common use cases:
- User account email addresses
- Contact information in entities
- Email notification recipients
- Authentication and identity management
Methods
Parse(string?, IFormatProvider?)
Converts the string representation of an email address to its EmailAddress equivalent. A return value indicates whether the conversion succeeded.
public static EmailAddress Parse(string? s, IFormatProvider? provider)
Parameters
sstringA string containing an email address to parse.
providerIFormatProviderAn object that provides culture-specific formatting information (not used for email parsing).
Returns
- EmailAddress
An EmailAddress equivalent to the email address contained in
s.
Remarks
This method implements the IParsable<TSelf> interface, providing standard .NET parsing behavior. For safer parsing without exceptions, use TryParse(string?, IFormatProvider?, out EmailAddress) or TryCreate(string?, string?).
Exceptions
- FormatException
Thrown when
sis not in a valid email format.
TryCreate(string?, string?)
Attempts to create an EmailAddress from the specified string.
public static Result<EmailAddress> TryCreate(string? emailString, string? fieldName = null)
Parameters
emailStringstringThe email address string to validate.
fieldNamestringOptional field name to use in validation error messages. If not provided, defaults to "email" (camelCase).
Returns
- Result<EmailAddress>
- Success with the EmailAddress if the string is a valid email
- Failure with a ValidationError if the email is invalid or null
Examples
// Basic usage
var result = EmailAddress.TryCreate("user@example.com");
// With custom field name for validation errors
var result2 = EmailAddress.TryCreate(userInput, "contactEmail");
// In a validation chain
var user = EmailAddress.TryCreate(request.Email, nameof(request.Email))
.Combine(FirstName.TryCreate(request.FirstName))
.Bind((email, name) => User.Create(email, name));
Remarks
This method performs comprehensive email validation using a regex pattern that matches RFC 5322 email address syntax. The validation is case-insensitive.
Activity tracing is automatically enabled for this method, allowing you to monitor email validation performance and success rates in application insights or other observability platforms.
TryParse(string?, IFormatProvider?, out EmailAddress)
Tries to parse a string into an EmailAddress.
public static bool TryParse(string? s, IFormatProvider? provider, out EmailAddress result)
Parameters
sstringThe string to parse.
providerIFormatProviderAn object that provides culture-specific formatting information (not used for email parsing).
resultEmailAddressWhen this method returns, contains the EmailAddress equivalent of the string, if the conversion succeeded, or
nullif the conversion failed.
Returns
- bool
trueifswas converted successfully; otherwise,false.
Remarks
This method implements the IParsable<TSelf> interface, providing standard .NET try-parse pattern. This is a safe alternative to Parse(string?, IFormatProvider?) that doesn't throw exceptions.