201

Possible Duplicate:
Best practices for validating email address in Objective-C on iOS 2.0?

I am developing an iPhone application where I need the user to give his email address at login.

What is the best way to check if an email address is a valid email address?

Community
  • 1
  • 1
raaz
  • 12,410
  • 22
  • 64
  • 81
  • valid email in that it is user@mac.com or valid in that it is a real email that exists and will accept mail? – PurplePilot Jun 29 '10 at 10:07
  • 1
    I want both, if abc@xyz.com is valid or not or wheather user give any invalid id(e.g. abc.com) Also i want to check abc@xyz.com is a real email that will accept mail. – raaz Jun 29 '10 at 10:18
  • 3
    there's no way to check the second condition. To check if a string is a valid email just scan it to see if '@' and . is there – dusker Jun 29 '10 at 10:47

4 Answers4

553

Good cocoa function:

-(BOOL) NSStringIsValidEmail:(NSString *)checkString
{
   BOOL stricterFilter = NO; // Discussion http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/
   NSString *stricterFilterString = @"^[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$";
   NSString *laxString = @"^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$";
   NSString *emailRegex = stricterFilter ? stricterFilterString : laxString;
   NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
   return [emailTest evaluateWithObject:checkString];
}

Discussion on Lax vs. Strict - http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/

And because categories are just better, you could also add an interface:

@interface NSString (emailValidation) 
  - (BOOL)isValidEmail;
@end

Implement

@implementation NSString (emailValidation)
-(BOOL)isValidEmail
{
  BOOL stricterFilter = NO; // Discussion http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/
  NSString *stricterFilterString = @"^[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$";
  NSString *laxString = @"^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$";
  NSString *emailRegex = stricterFilter ? stricterFilterString : laxString;
  NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
  return [emailTest evaluateWithObject:self];
}
@end

And then utilize:

if([@"emailString@email.com" isValidEmail]) { /* True */ }
if([@"InvalidEmail@notreallyemailbecausenosuffix" isValidEmail]) { /* False */ }
BadPirate
  • 25,802
  • 10
  • 92
  • 123
  • Worked nice until now. Today our tester found a bug `a@a..com` shows valid email. – Warif Akhand Rishi Jul 17 '13 at 10:48
  • 3
    I'm using `NSString *stricterFilterString = @"^[_A-Za-z0-9-+]+(\\.[_A-Za-z0-9-+]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,4})$";` – Warif Akhand Rishi Jul 17 '13 at 10:50
  • 3
    Thanks @WarifAkhandRishi -- I've updated the strings to handle your negative test case. – BadPirate Jul 19 '13 at 22:50
  • does this emailregex allow spanish or so to speak non-english characters. My app is supporting more than 3 languages so i need regex which works on all language.something works on unicode. – harshit2811 Mar 22 '14 at 07:53
  • @harshit2811 - From the discussion link - ??@??web.jp – International characters in domains and user names are already being normalized to ascii friendly code by browsers and e-mail clients, so they are being used regularly, however if you are checking before that normalization occurs, these sorts of e-mail addresses will get tossed – BadPirate Mar 24 '14 at 18:46
  • Ok.. So i just have to check whether "@" and "." is available in email address when user types the email in input field? – harshit2811 Mar 25 '14 at 04:05
  • Trying this and it keeps crashing... calling it like so [self NSStringIsValidEmail:textToCheck] --am I doing something wrong? – Lion789 Apr 20 '14 at 02:05
  • Looks like you are calling it correct lion. Whats the crash? – BadPirate Apr 22 '14 at 00:20
  • 9
    Or in swift ;) `func isValidEmail(checkString:NSString, strictFilter strict:Bool)->Bool{ var stricterFilterString = "[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}"; var laxString = ".+@([A-Za-z0-9]+\\.)+[A-Za-z]{2}[A-Za-z]*"; var emailRegex = strict ? stricterFilterString : laxString; var emailTest:NSPredicate = NSPredicate(format:"SELF MATCHES %@", emailRegex); return emailTest.evaluateWithObject(checkString); }` – Juan Carlos Ospina Gonzalez Jul 09 '14 at 12:09
  • 4
    new TLDs like .museum and .travel will not pass the strict test. – mahboudz Jul 12 '14 at 20:58
  • There is an error in the laxString: It does not accept: @t-online.de adresses. It should be: NSString *laxString = @".+@([A-Za-z0-9]+\\.)+[A-Za-z]{2}[A-Za-z]*"; sth like: SString *laxString = @".+@([A-Za-z0-9.-]+\\.)+[A-Za-z]{2}[A-Za-z]*"; – Berni Jul 25 '14 at 10:02
  • @Berni - I mention this in the discussion the website, the "Lax" String allows for addresses like .museum and .travel – BadPirate Aug 04 '14 at 18:42
  • @BadPirate OK. But the Problem is about the - (dash) in de Host: like t-online.de – Berni Aug 06 '14 at 20:42
  • Thank you. But the laxString return an error with the email: John..Doe@example.com. This email shouldn't be accepted as described in http://en.wikipedia.org/wiki/Email_address#Local_part – sahara108 Sep 10 '14 at 04:11
  • @sahara108 - Are you saying that the lax string returns john..doe@example.com as valid, even though it isn't? We are being lax :) – BadPirate Sep 12 '14 at 19:58
  • Yes, the john..doe@example.com should not be valid. Sorry, what do you mean lax. – sahara108 Sep 14 '14 at 09:33
  • @sahara108 I wrote the Lax statement to capture most valid emails and get email that is the general shape of an email. tricks like eliminating two periods in a row are a little fancy :) Have you got an alternative regular expression to suggest? – BadPirate Sep 15 '14 at 21:11
  • I am not good at regex :(. I just use `rangeOfString:@".."` to check it. – sahara108 Sep 16 '14 at 02:22
  • In `swift language` This link very useful for Validation email http://stackoverflow.com/questions/5428304/email-validation-on-textfield-in-iphone-sdk/28852348#28852348 – Ilesh P Mar 05 '15 at 12:35
  • Does anyone know of a regex that will work for international email addresses? (cyrillic, etc.) – cynistersix Mar 30 '15 at 18:57
  • 1
    @cynistersix - Non-ASCII isn't officially supported by all mail servers / clients yet. Ideally if you spot non-ASCII characters, you would encode it to a supported alias (ie.. Punycode) http://stackoverflow.com/a/760318/285694 - And verify the result. – BadPirate Mar 30 '15 at 19:02
  • Beginner question but what constitutes passing if you just say [self NSStringIsValidEmail:textToCheck] what is it supposed to return and what is best way to call it. when I try: if ([self NSString..]) {} it does not work. – user1904273 May 18 '15 at 23:48
  • @user1904273 - If you put that method into a class call with [self NSStringIsValidEmail:@"someStringThatMightBe@email.com"] -- It will return true if the passed string is a valid email (false otherwise) and should work in the case you put above (assuming textToCheck in your case is in fact a valid email. – BadPirate May 19 '15 at 22:59
  • this accepts aa@aaa@aaa.com – Joan Cardona Jul 09 '15 at 13:17
  • @JoanCardona - The addition of ^ and $ into the regular expression should have fixed this (and appears to in my tests) – BadPirate Jul 13 '15 at 21:34
  • +5 years old and still rocking! I've combined strict and lax with NSCompoundPredicate orPredicateWithSubpredicates and it's working great, thnx. – Rick van der Linde Dec 09 '15 at 13:26
  • It accepts these cases, "test@@test.com" "test.@test.com" ".test.@test.com" "@test@a.com" – Omer Waqas Khan Jan 17 '16 at 21:06
  • 2
    this validation is getting faild if I am entering emai laddress with space charector – Gajendra Rawat Feb 25 '16 at 07:00
  • 1
    @morroko: email addresses should not contain a space – Matthew Cawley Feb 29 '16 at 11:17
  • But, still this function will accept "a@a.coz" ???? – Vanilla Boy Apr 18 '16 at 16:13
  • @VanillaBoy what's wrong with that address? Looks valid to me. Note, function is far too simple to do domain validation as well. Valid top level domain list is constantly expanding, so only way to do that would be some sort of network or DNS validation. – BadPirate Apr 18 '16 at 18:42
  • Please note this case "123@qq.com". This should result false. Because @ and @ is different. The code can not handle this case. – Hugo Jun 17 '16 at 07:52
  • still accept a..@gmail.com – Ishwar Hingu Jun 29 '16 at 08:11
  • Opinionated but concise Swift 3: ` extension String { func isValidEmail()->Bool{ return NSPredicate(format:"SELF MATCHES %@", ".+@([A-Za-z0-9]+\\.)+[A-Za-z]{2}[A-Za-z]*").evaluate(with: self); } }` – PLJNS Sep 24 '16 at 21:25
  • What about this email address. "hemant....@gmail.com" Returning valid email address –  Jun 28 '17 at 05:23
  • @HPM -- Yeah, looks like the RFC allows single periods but not multiple in a row in the local portion of the email address. -- This would probably make for a pretty challenging regular expression :) If you've got one that covers all the same but gets the double period case then feel free to suggest. – BadPirate Jun 29 '17 at 23:12
  • It accepts `@mail.com`. Is that correct? – Mathi Arasan Jul 28 '17 at 06:14
  • @BadPirate. Check with this @"[A-Z0-9a-z]+([._%+-]{1}[A-Z0-9a-z]+)*@[A-Za-z0-9-]+.{0,1}[A-Za-z]{2,}" –  Jul 28 '17 at 12:49
  • So you aren't allowing "root@localhost"? That is a valid e-mail address. – Deantwo Nov 01 '17 at 09:16
  • While it might be for another programming language, I suggest reading this: https://stackoverflow.com/a/1374644/5815327 – Deantwo Nov 01 '17 at 09:20
  • In this Have bug Its accepting @@@@@@gmail.com – Anup Gupta Mar 22 '18 at 13:25
7

To check if a string variable contains a valid email address, the easiest way is to test it against a regular expression. There is a good discussion of various regex's and their trade-offs at regular-expressions.info.

Here is a relatively simple one that leans on the side of allowing some invalid addresses through: ^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$

How you can use regular expressions depends on the version of iOS you are using.

iOS 4.x and Later

You can use NSRegularExpression, which allows you to compile and test against a regular expression directly.

iOS 3.x

Does not include the NSRegularExpression class, but does include NSPredicate, which can match against regular expressions.

NSString *emailRegex = ...;
NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
BOOL isValid = [emailTest evaluateWithObject:checkString];

Read a full article about this approach at cocoawithlove.com.

iOS 2.x

Does not include any regular expression matching in the Cocoa libraries. However, you can easily include RegexKit Lite in your project, which gives you access to the C-level regex APIs included on iOS 2.0.

benzado
  • 82,288
  • 22
  • 110
  • 138
6

Heres a good one with NSRegularExpression that's working for me.

[text rangeOfString:@"^.+@.+\\..{2,}$" options:NSRegularExpressionSearch].location != NSNotFound;

You can insert whatever regex you want but I like being able to do it in one line.

jasongregori
  • 11,451
  • 5
  • 43
  • 41
  • This is an even better option in Swift, since `rangeOfString()` returns an optional, which is `nil` if there's no match – Dov Mar 08 '15 at 20:13
3

to validate the email string you will need to write a regular expression to check it is in the correct form. there are plenty out on the web but be carefull as some can exclude what are actually legal addresses.

essentially it will look something like this

^((?>[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+\x20*|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*"\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_`{|}~]+)+|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$

Actually checking if the email exists and doesn't bounce would mean sending an email and seeing what the result was. i.e. it bounced or it didn't. However it might not bounce for several hours or not at all and still not be a "real" email address. There are a number of services out there which purport to do this for you and would probably be paid for by you and quite frankly why bother to see if it is real?

It is good to check the user has not misspelt their email else they could enter it incorrectly, not realise it and then get hacked of with you for not replying. However if someone wants to add a bum email address there would be nothing to stop them creating it on hotmail or yahoo (or many other places) to gain the same end.

So do the regular expression and validate the structure but forget about validating against a service.

PurplePilot
  • 6,652
  • 7
  • 36
  • 42
  • That's one hell of a regular expression. To use it, you'll either need to target iOS 4.0 which has the NSRegularExpression class, or use one of the many regex static libraries compiled for previous versions of iOS. – Alex Jun 29 '10 at 15:31
  • Actually, you can use NSPredicate, which can handle regular expressions. – BadPirate Sep 02 '10 at 23:12