We help IT Professionals succeed at work.

C email validation

Ali B
Ali B asked
on
Hi, I was looking for different approaches in validating emails in C
I wasn't able to find so many examples like other languages. This is one example
http://etutorials.org/Programming/secure+programming/Chapter+3.+Input+Validation/3.9+Validating+Email+Addresses/

Can anyone provide me with other good examples in C?
Comment
Watch Question

I studied the example you posted and it's pretty good.  I'd have written it differently (with less continues and more elses) but I suspect the author was trying very hard to optimize the function for speed.

One change I'd make is to reverse how the strchr() is done if you are looking to optimize for speed.  It might be better to use strcspn at the top of the function.  However, I haven't seen the implementation code for strcspn.  Another approach could be to use a switch statement.

I'm guessing optimization is desired since the project is to be in C and the best reason I can think of to write such a project in C is that you are trying to go very fast.  (But why would you be trying to go very fast?)

But then I don't know why you don't like the function you've already found.

Why don't you like the function you've already found?
Ali BIT Consultant

Author

Commented:
Well.. the reason is that I'm good in OOP but not C.
I have to do this task in C. However, the function I found doesn't have enough comments so I can fully understand it. I cannot modify it to meet other validation requirements simply because I don't understand it.
I studied the code you found and it makes sense to me.  I can help you to understand it.

Can you tell me what your other validation requirements are?
Ali BIT Consultant

Author

Commented:
the email grammar i'm trying to apply is as following:
email format: local@domain

local part must start with a letter. can contain numbers, dashes, or dots. must end with letter or number.
no consecutive dashes or dots are allowed

e.g. (correct format)
ab.c2@x.x
a1@x.x
a.b.c@x.x
a-1@x.x

e.g. (invalid)
1a@x.x
a--@x.x
a..@x.x

I think if I how get the local part i will be able to do the domain part.

the problem as i mentioned, the code doesn't have comments so a beginner like me would understand which condition doing what.
Confirming -- the only legal characters in the local are letters, numerals, dashes or dots.  That is, joe_smith@foo.com is illegal.  Right?

Also, is this legal or not?

joe-.smith@foo.com
Ali BIT Consultant

Author

Commented:
yes underscore is illegal

-. or .- is illegal as well
Here's some code I wrote but haven't tested well at all.  However, it's setup so you can run some test cases.  (I'd test more but I'm in a real time crunch right now.)

// Function to validate an e-mail address with the extra rules
// that user name part 
// must begin with a letter, 
// must end with a letter or numeral,
// may only consist of letters, numerals, dashes and dots and
// may not have consequtive dashes or dots.
// Note -. and .- are illegal consequtive dash/dots.
//
// Original code found on etutorials.org
// Modified to meet the needs of another member at Experts Exchange.
//
// Last modification: Hugh McCurdy 21-Aug-2012

#include <string.h>
#include <ctype.h>
#include <stdio.h>

#define TRUE (1)
#define FALSE (0)

// return TRUE if and only if c is a period or a dash.
int isdotdash ( const char c )
{
  switch ( c )
  {
    case '.':
    case '-':
      return TRUE;
  }
  return FALSE;
} // isdotdash

int spc_email_isvalid(const char *address) 
{
  int        count = 0;
  const char *c, *domain;
  static char *rfc822_specials = "()<>@,;:\\\"[]";

  c = address;

  // First character must be a letter.
  if ( ! isalpha ( *c ))
    return 0;

  for ( c = address + 1;  *c && *c != '@';  c++ ) 
  {
    // dot/dash check.  Consequtive illegal.  (--, .., .- and -. illegal)
    if ( isdotdash ( *c ))
    {
      if ( isdotdash ( *( c - 1 )))
        return 0;
    }
    // if not a dot/dash then only alphanumeric characters are legal.
    else if ( ! isalnum ( *c ))
      return 0;
  } // for

  // Make sure the current character is an @
  if ( *c != '@' )
    return 0;

  // Now make sure the character before the @ is a alphanumeric.
  if ( ! isalnum ( *(c - 1 )))
    return 0;
  

  /* next we validate the domain portion (name@domain) */
  if (!*(domain = ++c)) return 0;
  do 
  {
    if (*c == '.') 
    {
      if (c == domain || *(c - 1) == '.') return 0;
      count++;
    }
    if (*c <= ' ' || *c >= 127) return 0;
    if (strchr(rfc822_specials, *c)) return 0;
  } while (*++c);

  return (count >= 1);
} // spc_email_isvalid()


// main() only used for testing.
int main ( void )
{
  static const char *list[] =
  {
    "setter@volleyball.net",
    "irish__setter@volleyball.net",
    "1setter@volleyball.net",
    "\0"
  };
  int i;

  for ( i = 0; *list [ i ]; i++ )
  {
    printf ( "%s %s\n", spc_email_isvalid ( list[i] ) ? "PASS" : "FAIL", list[i] );
  }

} // main()

Open in new window

Thanks for the points.  I ran a few more tests.

PASS setter@volleyball.net
FAIL irish__setter@volleyball.net
FAIL 1setter@volleyball.net
PASS setter1@volleyball.net
PASS setter.1@volleyball.net
FAIL setter..1@volleyball.net
FAIL setter#1@volleyball.net

Please let us/me know if you need additional assistance.