Skip to main content

EmailValidatorExtensions

Namespace: RA.Utilities.Application.Validation.Extensions

EmailValidatorExtensions adds a reusable FluentValidation rule that validates a string property through the Email value object of RA.Utilities.Core.ValueObjects — so request validation and the domain share one set of email rules.

🎯 Purpose and Design​

1. Value-Object-Backed Rule​

MustBeValidEmail chains onto any string rule and validates the value by constructing an Email instance behind the scenes:

public class RegisterUserValidator : AbstractValidator<RegisterUserRequest>
{
public RegisterUserValidator()
{
RuleFor(x => x.Email).MustBeValidEmail();
}
}

Any input the Email value object rejects fails the rule for that property path: null, empty or whitespace, addresses over 254 characters, and values that don't match the email format.

The rule is declared as a C# 14 extension member on IRuleBuilder<T, string>; the calling syntax is unchanged.

2. Requiredness Is Enforced​

Because the Email constructor rejects null, empty, and whitespace input, this rule also fails on missing values — the value doubles as a required check.

3. Failure Message​

The rule surfaces the BadRequestException message of the value object — the generic "The request is invalid." — rather than the specific validation detail. Chain WithMessage to provide a property-specific message:

RuleFor(x => x.Email)
.MustBeValidEmail()
.WithMessage("'{PropertyName}' must be a valid email address.");

✔️ Valid vs Invalid​

ValueResult
"user@gmail.com"✅ Valid
" User@Gmail.com "✅ Valid (normalized to user@gmail.com)
null❌ Invalid (unlike the format-only currency rule)
"" / " "❌ Invalid
"not-an-email"❌ Invalid
> 254 characters❌ Invalid

🧠 Summary​

EmailValidatorExtensions delegates email validation to the Email value object, keeping request validation and domain rules in sync. Unlike shape-only format rules, it fails on missing values and reports failures with the generic BadRequestException message.