5
\$\begingroup\$

I was given this project and have changed a lot of code on it, now I am going over the code to make sure that I know what everything does and can maintain it efficiently, and to make sure I want my name on it.

Here is the method they have been using to validate e-mail addresses from a textbox input.

private string ValidateEmailAddresses(string addressesIn)
{
    MailMessage msg = new MailMessage();

    if (!String.IsNullOrWhiteSpace(addressesIn))
    {
        string[] allAddresses = addressesIn.Split(";,".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

        foreach (string addy in allAddresses)
        {
            try
            {
                msg.To.Add(addy);
            }
            catch (FormatException)
            { }
        }
    }
    return msg.To.ToString();
}

Is there a better way to accomplish this task?

\$\endgroup\$
  • 1
    \$\begingroup\$ It rejects valid addresses like "Smith, Jane"@example.com (not that I’ve ever seen anyone use such an address, but I believe it is valid). \$\endgroup\$ – icktoofay Dec 24 '14 at 0:13
  • \$\begingroup\$ Not sure if it is valid or not but if a FormatException is being thrown then that's framework behavior, which means you'd be SOL trying to send an email to that address anyway. \$\endgroup\$ – moarboilerplate Dec 24 '14 at 0:24
  • 1
    \$\begingroup\$ Not sure if this is an answer or not, but using exceptions as a code path is an expensive proposition. Basically, the runtime has to collect a fair amount of information (the stack being the most expensive) for each FormatException. Thus, I would not use this in a performance-sensitive area of the application. \$\endgroup\$ – Heretic Monkey Dec 24 '14 at 5:19
  • \$\begingroup\$ I think this is one of the smart way to validate and filter out non-complaint email format. A bit inefficient but it is only use on data entry, if it were to be use in a loop to validate thousands of emails then a regular expression match would me more appropriate. \$\endgroup\$ – Tien Dinh Dec 27 '14 at 17:44
5
\$\begingroup\$
  • Well, it really depends on why addressesIn is a string. If it's input from the user, as I suspect, it is a fine method.

  • If I was to be a harsh critic I would ask why a method named "Validate" returns a string.

  • I think if you rename the method to like "ScrubEmailAddresses" or "SanitizeEmailAddresses" and envision it in an app that lets a user input email addresses to send an email to, it's kind of nifty. Basically instead of a roll-your-own-validations approach this says "hey, let the framework do it for me!" by taking advantage of the fact that .NET will just throw a FormatException if you try to add an invalid address. It's a fairly decent server-side equivalent to a RegularExpressionValidator using the predefined email regex. I also agree with Mike McCaughan's comment mentioning there is a resource hit when having the framework throw an exception.

\$\endgroup\$
  • 2
    \$\begingroup\$ I don't think the latter part is harsh at all; it's a great question. As it stands, this method has an unfavorably high WTF factor given its small size and scope. \$\endgroup\$ – Patrick Dec 24 '14 at 0:36
  • 1
    \$\begingroup\$ I think if you rename the method to like "ScrubEmailAddresses" or "SanitizeEmailAddresses" and envision it in an app that lets a user input email addresses to send an email to, it's kind of nifty. Basically instead of a roll-your-own-validations approach this says "hey, let the framework do it for me!" by taking advantage of the fact that .NET will just throw a FormatException if you try to add an invalid address. It's a fairly decent server-side equivalent to a RegularExpressionValidator. \$\endgroup\$ – moarboilerplate Dec 24 '14 at 0:47
  • \$\begingroup\$ that should be edited into your answer @moarboilerplate. that is a good point \$\endgroup\$ – Malachi Dec 24 '14 at 14:27
2
\$\begingroup\$

One option, you have, is to make the TextBox multiline and instruct the user to type one email address per line. By changing your method to accept a string array, you won't need to split the string just pass in the Lines property of the TextBox:

private string ValidateEmailAddresses(string[] addressesIn)
{
    MailMessage msg = new MailMessage();

    if (addressesIn.Length != 0)
    {

        foreach (string addy in addressesIn)
        {
            try
            {
                msg.To.Add(addy);
            }
            catch (FormatException)
            { }
        }
    }
    return msg.To.ToString();
}

A further thought, rather than returning the string of addresses, put this code in the Validate event handler for the TextBox. Then in the Catch block build a multiline string of the failed email addresses to display in a MessageBox to prompt the user to fix or delete the offending lines. Once all the addresses are validated, simply use the data in the textbox.

\$\endgroup\$
1
\$\begingroup\$

As icktoofay points out:

It rejects valid addresses like "Smith, Jane"@example.com

Check out this post for an interesting explanation without having to actually read the RFC.

The problem is with this section of code

addressesIn.Split(";,".ToCharArray() ...

As you are splitting on ; and ,, it will split on any quoted ; or , characters within the email address local part such as the one found in the above email address.

With the exception of that, this is a good piece of code to find out if you have a possibly valid email address. Yes, control flow logic based on an exception is generally bad, however unless this is a massive bulk operation it will not cause anything more than a minor performance hit. At the end of the day, the only way to find out if it is truly valid is to send a message to it and ask the recipient to click a link containing a cryptographically secure random sequence. However, some anti-spam systems will automatically follow links in emails so this does not validate whether you have a human being at the other end, so you could get them to manually enter a random code instead on a form linked from the email.

To summarise, you need to find a method of splitting the email addresses without accidentally splitting on quoted sections. Yes, you'd be mad to purposely register the email address "this;will,never,be;accepted;anywhere"@example.com or to set one up for one of your employees with an address like this. However, we had a customer using one of our systems recently and they requested a change to the email validation routine as their customer had an employee with an email address like David.O'leary@example.com which our system was rejecting and they could not register.

This is why I like your approach of relying on the built in MailAddress object to validate, which as also suggested in the first comment in this article: Don’t trust the .NET web forms email regex validator (or most others).

\$\endgroup\$
  • \$\begingroup\$ remote.org/jochen/mail/info/chars.html Email Addresses don't allow , or ; in them \$\endgroup\$ – Malachi Jan 2 '15 at 14:27
  • 2
    \$\begingroup\$ @Malachi: That site shows whether they can or should be allowed not whether they are allowed by the specification. For , it states RFC2822 allowes [sic] their use if they are inside double quotes and for ; it states The semicolon could theoretically be used, but must be quoted. The spec allows almost any character in a quoted string. Yes, you'd probably be mad to have these characters in your email address, but it does happen (we recently had to change a validation routine as one of our customer's user's had the ' character). \$\endgroup\$ – SilverlightFox Jan 2 '15 at 14:46
  • \$\begingroup\$ I see. I should read more and scan less. I don't think I am going to worry about these corner cases because the addresses are going to be a select handful, this site is not open to the public. \$\endgroup\$ – Malachi Jan 2 '15 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.