Check email syntax and normalize the domain without sending a message.
dotnet add package RecursiveAI.OneContactRequires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.
using RecursiveAI.OneContact; bool valid = EmailAddress.TryParse( "jane@example.com", out var email); Console.WriteLine(valid);
TrueDownload this example (.zip): unzip, then dotnet run.
Full program
using RecursiveAI.OneContact; foreach (string input in new[] { "Jane <jane@EXAMPLE.COM>", "not-an-email", "a..b@example.com" }) { if (EmailAddress.TryParse(input, out var email)) Console.WriteLine($"{input} => {email.Canonical}"); else Console.WriteLine($"{input} => invalid"); }
dotnet run prints:
Jane <jane@EXAMPLE.COM> => jane@example.com not-an-email => invalid a..b@example.com => invalid
Rejected mailbox text makes TryParse return false; Parse instead throws ContactParseException. This is syntax validation, not a delivery check.
Variations
Read an internationalized domain as ASCII and Unicode:
using RecursiveAI.OneContact; var email = EmailAddress.Parse("info@Bücher.example"); Console.WriteLine(email.Canonical); Console.WriteLine(email.UnicodeDomain);
info@xn--bcher-kva.example bücher.example
Related recipes
- Validate a phone number in C#
- Format a phone number as E.164 in C#
- Parse a phone number in C#
- Extract email addresses from text in C#
The short answer
Use EmailAddress.TryParse to check whether OneContact can read one mailbox. It returns a Boolean and, on success, a parsed value with the canonical address, display name and flags. This checks syntax and domain structure. It does not verify that a mailbox exists or that the person entering it controls it.
The example accepts Jane <jane@EXAMPLE.COM> and normalizes it to jane@example.com. That is intentional: this parser accepts both a bare address and a display name with an address. If your form requires a bare address only, make that an explicit form policy rather than assuming every successful parse had no display name.
How can I validate email addresses in C#?
Pick the rule your form needs before deciding what “valid” means. OneContact reads one mailbox, including quoted local parts, comments and internationalized domains. It does not treat a list of recipients or a mail group as one mailbox. The email documentation spells out the accepted syntax and the flags returned for it.
The canonical value keeps the local part as written, including meaningful quotes, and lowercases the domain. Internationalized domains become ASCII A-labels; UnicodeDomain exposes the readable form. The variation demonstrates both outputs. Don’t lowercase the whole canonical value merely because domains are case-insensitive: the documented canonicalization preserves the local part.
Read flags when your application needs stricter rules. For example, HasDisplayName, QuotedLocalPart, SingleLabelDomain and ObsoleteSyntax describe accepted text. Length issues are reported with ExceedsLengthLimit and warnings, not parse refusal. A successful Boolean parse therefore does not imply that every delivery-system length constraint passed. Define whether to reject or warn about those cases in your application.
Hints such as PossibleTypo and TypoSuggestion are not automatic corrections. Offer a suggestion to the user instead of silently replacing a domain. Likewise, role-account and disposable-domain flags describe classifications; they do not establish who owns an address.
Do I need a regex to validate an email address in C#?
Not for the examples here. The parser supplies the syntax check and a normalized value in the same operation. A simple pattern can be a form-specific precheck, but it should not become an undocumented substitute for the accepted mailbox grammar.
Microsoft’s email-format guidance makes the distinction explicit: checking structure is not a substitute for verifying that the address exists, and it recommends sending a test email. OneContact itself opens no network connection. Build any confirmation flow outside the parser.
Finally, validation and extraction are different jobs. A validator expects the whole input to be one mailbox. A paragraph containing several addresses is not one mailbox, even when every address inside it is well formed. Use the text extraction recipe for that input, then apply your acceptance rules to each extracted value. Keep the original text alongside the canonical value when you need to explain a rejected import row or let a user edit what they entered.
As the OneContact release overview states: “Version 1.0 runs on rules and markup alone.”