20

I want to be able to do this:

string email = "some@email.com";
bool isValid = IsValidEmail(email);
//returns true

...but use the logic Microsoft has already given us in EmailAddressAttribute.

There are hundreds of good and bad implementations of IsValidEmail out there, and I don't want to add my own, when I can use something, Microsoft has already thought about. It stands to reason, that they will do a better job than me.

In recent ASP.Net versions, we have System.ComponentModel.DataAnnotations, which provides us with the excellent EmailAddressAttribute, that lets us decorate our models like this:

public class SomeModel
{
    [EmailAddress]
    public string Email { get; set; }
}

The class is sealed, so I cannot call EmailAddressAttribute.IsValid()

Is there a good way I can utilize what Microsoft has already done? Is there a method somewhere in the .Net framework, that let's me test strings against data-annotations, that I have overlooked?

Something along the lines of..:

var emailChecker = new DataAnnotationsChecker<EmailAddressAttribute>();
string email = "some@email.com";
bool isValid = emailChecker.IsValid(email);
//returns true

If you cannot imagine why I would want this, think about getting a List and want to check which ones are valid emails.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Kjensen
  • 12,447
  • 36
  • 109
  • 171

3 Answers3

27

You could use the EmailAddressAttribute to do the validation.

The sealed means that you cannot create another class that inherits from it. Doesn't mean you cannot use it.

Created some unit tests and works fine

[TestMethod]
public void Should_Use_Email_Address_Attribute_To_Validate_Email() {
    var emailChecker = new System.ComponentModel.DataAnnotations.EmailAddressAttribute();
    string email = "some@email.com";
    bool isValid = emailChecker.IsValid(email);
    Assert.IsTrue(isValid);
}

[TestMethod]
public void Should_Use_Email_Address_Attribute_To_Invalidate_Email() {
    var emailChecker = new System.ComponentModel.DataAnnotations.EmailAddressAttribute();
    string email = "some@emai l.com";
    bool isValid = emailChecker.IsValid(email);
    Assert.IsFalse(isValid);
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 5
    I would have sworn, I already tried that... But of course this does in fact work. I feel silly now. Thanks. :) – Kjensen Apr 29 '16 at 22:25
  • 1
    A serious question here: Why is this not the approved/accepted method of checking email addresses in .Net? Microsoft is going to do email validation better than any one of us will. – Shai Cohen Feb 12 '17 at 03:24
  • @ShaiCohen doesn't mean they can't make mistakes as well like the rest of us. We're all coders. It does save you from having to write one yourself. Here are two completely different implementations of the same attribute [corefx](https://github.com/dotnet/corefx/blob/master/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs), [mvc](https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/Microsoft.Web.Mvc/EmailAddressAttribute.cs) – Nkosi Feb 12 '17 at 03:53
  • 7
    I'll add something I discovered relative to what is "valid". With the sample email address "mark@gmailcom" - Checking validity with System.Net.Mail.MailAddress returns true because technically it is. EmailAddressAttribute IsValid returns false because the dot is missing. For my purposes the address is not valid without the dot in the domain part. – mohnston Aug 07 '17 at 20:06
3

EmailAddressAttribute IS NOT SAFE !!!

They claim that .NET is safe and secure! But if you don't read the source code, you will be misled and make mistakes!

The following code, are you serious???

https://source.dot.net/#System.ComponentModel.Annotations/System/ComponentModel/DataAnnotations/EmailAddressAttribute.cs,c3ae85dfd8a9f58c

public override bool IsValid(object? value)
{
    if (value == null)
    {
        return true;
    }

    if (!(value is string valueAsString))
    {
        return false;
    }

    // only return true if there is only 1 '@' character
    // and it is neither the first nor the last character
    int index = valueAsString.IndexOf('@');

    return index > 0 &&
           index != valueAsString.Length - 1 &&
           index == valueAsString.LastIndexOf('@');
}

See how the people at Microsoft responded. They just leave the safety issues alone and claim to have designed such a trap for us to step on!

https://github.com/dotnet/runtime/issues/65968

huang
  • 919
  • 11
  • 22
1

Use MailAddress
This is a useful technique for reading and validating an email address, even from 'Elmer Fudd <e.fudd@example.com>' styled inputs (such as those copy-pasted from email clients).

private string? ExtractEmailAddress(string raw)
{
    try
    {
        var address = new MailAddress(raw);
        return address.Address;
    }
    catch (Exception)
    {
        return null;
    }
}

I also use [EmailAddress] attribute to indicate the required type to API documentation.

Peter L
  • 2,921
  • 1
  • 29
  • 31