167

What is the cleanest way to validate an email address that a user enters on iOS 2.0?

NOTE: This is a historical question that is specific to iOS 2.0 and due to its age and how many other questions are linked to it it cannot be retired and MUST NOT be changed to a "modern" question.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • I am looking for a cocoa solution. I understand the validity of emails and the rules around validating emails. However since RegEx is not easily accessible on Cocoa Touch, I am looking for a Cocoa Touch solution to validation. Not a list of the rules around validation. – Marcus S. Zarra Apr 28 '09 at 23:30
  • So far the best code suggestion I have found is using RegExKitLite and regular expressions. Fortunately it is less painful than it sounds. – Marcus S. Zarra Apr 29 '09 at 14:31
  • See comments below about using NSRegularExpression for apps not supporting os < 4.0. – beOn Feb 27 '11 at 19:59
  • Note that this was asked in 2009 when there was no NSRegularExpression on the iPhone. – Marcus S. Zarra Mar 06 '11 at 19:46
  • People using iOS 3.0 can use `NSPredicate`; people using iOS 4.0 can use `NSRegularExpression`. – benzado May 22 '11 at 20:46
  • 1
    Since this seems to be the canonical question regarding email address validation, it makes sense to update with improved answers as iOS matures. With that in mind, I've added an answer which uses iOS's `NSDataDetector` to validate email addresses: http://stackoverflow.com/a/23547905/257550 – memmons May 08 '14 at 16:53
  • This is the canonical question for iOS 2. `NSDataDetector` did not exist in iOS 2. – Marcus S. Zarra May 08 '14 at 17:10
  • 2
    This question appears to be off-topic because it is about iOS 2.0 which was deprecated years ago. – Nathan Eror May 20 '14 at 16:57

13 Answers13

354

The answer to Using a regular expression to validate an email address explains in great detail that the grammar specified in RFC 5322 is too complicated for primitive regular expressions.

I recommend a real parser approach like MKEmailAddress.

As quick regular expressions solution see this modification of DHValidation:

- (BOOL) validateEmail: (NSString *) candidate {
    NSString *emailRegex =
@"(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}"
@"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\"
@"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-"
@"z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5"
@"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-"
@"9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21"
@"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"; 
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES[c] %@", emailRegex]; 

    return [emailTest evaluateWithObject:candidate];
}
Community
  • 1
  • 1
catlan
  • 25,100
  • 8
  • 67
  • 78
  • 9
    Great but doesn't work on OS <3.0, because NSPredicate is not available. – Felixyz Oct 13 '09 at 12:58
  • 4
    Nice. Everyone forgets that NSPredicate can run regexps. – Rog Oct 14 '09 at 11:57
  • 5
    That is one very bad regexp. For instance, it will fail on people using the .museum top domain. Refer to this article: http://www.linuxjournal.com/article/9585 – Jonny Aug 27 '10 at 04:13
  • 1
    So apart from changing the end to {2,6}, what changes could be made to significantly improve this regex to make it work for most common cases? – Tomas Andrle Sep 01 '10 at 22:31
  • 18
    There's a more complete regex at http://cocoawithlove.com/2009/06/verifying-that-string-is-email-address.html that can be used instead of this simple one. – Tomas Andrle Sep 01 '10 at 22:49
  • 12
    Here is a very naive but liberal email regex as a Cocoa string: `@"[^@]+@[^.@]+(\\.[^.@]+)+"` If you need to verify an email address send a message to it and see if it succeeds. You will never verify it with any level of accuracy with a regex alone, so it's best not to piss of users and lose sign ups because of an unnecessarily strict regex. – Sami Samhuri Sep 13 '11 at 16:35
  • 2
    What about uppercase characters in the second regex? – Jakob May 13 '13 at 12:19
  • 2
    I'd +1 it if it weren't for all those spaces in the method declaration :p. – Kyle Clegg Sep 05 '13 at 01:41
  • Seems like it doesn't validate this kind of address properly : (email@domain..ca). I believe this is not a valid email address based on the RFC. – Alexandre Sep 11 '13 at 15:45
  • First one allows multiple (.) and in second one allows almost any characters in domain. Applying both together gives exact result. Thanku :) +1 – Baby Groot Oct 04 '13 at 12:41
  • I also need to eliminate email id with number like 123@gmail.com – venky Jan 29 '14 at 09:15
  • There are now TLDs longer than six characters, such as `.international` (13). – nobody May 19 '14 at 14:59
  • What is the part `[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]| \\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+` at the end supposed to allow? It is in alternation with the last decimal group of IPv4 address, which is rather strange. – nhahtdh Sep 29 '15 at 11:17
  • For those searching for a case-insensitive match simply prepend the given regex with `(?i)`. See http://userguide.icu-project.org/strings/regexp for reference – Leonid Usov Apr 25 '18 at 21:01
20

Read the RFC. Almost everyone that thinks they know how to parse/clean/validate an email address is wrong.

https://www.rfc-editor.org/rfc/rfc2822 Section 3.4.1 is very useful. Notice

dtext           =       NO-WS-CTL /     ; Non white space controls

                        %d33-90 /       ; The rest of the US-ASCII
                        %d94-126        ;  characters not including "[",
                                        ;  "]", or "\"

Yes, that means +, ', etc are all legit.

Community
  • 1
  • 1
Trey
  • 11,032
  • 1
  • 23
  • 21
  • Current as of May 2016: [RFC5322, section 3.4.1](https://tools.ietf.org/html/rfc5322#section-3.4.1) – leanne May 02 '16 at 22:44
17

The best solution I have found so far (and the one I ended up going with) is to add RegexKitLite To the project which gives access to regular expressions via NSString Categories.

It is quite painless to add to the project and once in place, any of the regular expression email validation logic will work.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
10

A good start is to decide what do you and do you not want to accept as an email address?

99% of of email addresses look like this: bob.smith@foo.com or fred@bla.edu

However, it's technically legal to have an email address like this: f!#$%&'*+-/=?^_{|}~"ha!"@com

There are probably only a handful of valid emails in the world for top-level domains, and almost nobody uses most of those other characters (especially quotes and backticks), so you might want to assume that these are all invalid things to do. But you should do so as a conscious decision.

Beyond that, do what Paul says and try to match the input to a regular expression like this: ^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$

That one will match pretty much everybody's email address.

Brandon Yarbrough
  • 37,021
  • 23
  • 116
  • 145
  • even though this answer was written in 2009 it still comes up very high in search results. i just wanted to add that this is no longer up to date and the above regex is a bit restrictive. for example, now you can have 4 digit or more top level domain – Jack Aug 06 '15 at 19:49
  • Good point, edited it to "at least 2 digits". Feel free to edit further if you like. – Brandon Yarbrough Aug 06 '15 at 19:57
7

This function is simple and yet checks email address more thoroughly. For example, according to RFC2822 an email address must not contain two periods in a row, such as firstname..lastname@domain..com

It is also important to use anchors in regular expressions as seen in this function. Without anchors the following email address is considered valid: first;name)lastname@domain.com(blah because the lastname@domain.com section is valid, ignoring first;name) at the beginning and (blah at the end. Anchors force the regular expressions engine to validate the entire email.

This function uses NSPredicate which does not exist in iOS 2. Unfortunately it may not help the asker, but hopefully will help others with newer versions of iOS. The regular expressions in this function can still be applied to RegExKitLite in iOS 2 though. And for those using iOS 4 or later, these regular expressions can be implemented with NSRegularExpression.

- (BOOL)isValidEmail:(NSString *)email
{
    NSString *regex1 = @"\\A[a-z0-9]+([-._][a-z0-9]+)*@([a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,4}\\z";
    NSString *regex2 = @"^(?=.{1,64}@.{4,64}$)(?=.{6,100}$).*";
    NSPredicate *test1 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex1];
    NSPredicate *test2 = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex2];
    return [test1 evaluateWithObject:email] && [test2 evaluateWithObject:email];
}

See validate email address using regular expression in Objective-C.

Geek
  • 413
  • 6
  • 4
7

While the focus on regular expressions is good, but this is only a first and necessary step. There are other steps that also need to be accounted for a good validation strategy.

Two things on top of my head are :

  1. DNS validation to make sure the domain actually exists.

  2. After dns validation, you can also choose to do an smtp validation. send a call to the smtp server to see if the user actually exists.

In this way you can catch all kinds of user errors and make sure it is a valid email.

Srikar Doddi
  • 15,499
  • 15
  • 65
  • 106
6
NSString *emailString = textField.text; **// storing the entered email in a string.** 
**// Regular expression to checl the email format.** 
NSString *emailReg = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; 
NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",emailReg]; 
if (([emailTest evaluateWithObject:emailString] != YES) || [emailStringisEqualToString:@""]) 
{ 
UIAlertView *loginalert = [[UIAlertView alloc] initWithTitle:@" Enter Email in" message:@"abc@example.com format" delegate:self 
cancelButtonTitle:@"OK" otherButtonTitles:nil]; 

enter code here

[loginalert show]; 
[loginalert release]; 
} 
If email is invalid, it will remind the user with an alert box. 
Hope this might be helpful for you all. 
hirak
  • 77
  • 1
  • 1
4

I have found that using a regular expression works quite well to validate an email address.

The major downside to regular expressions of course is maintainability, so comment like you have never commented before. I promise you, if you don't you will wish you did when you go back to the expression after a few weeks.

Here is a link to a good source, http://www.regular-expressions.info/email.html.

Paul Redman
  • 213
  • 4
  • 11
  • I implemented the second-last one on that page recently, and I'm quite happy with it. It works fine for a simple user@host.com email address, with no quotes or brackets for a full name. Works great for web form validation where people won't be typing that sort of thing in anyway. – zombat Apr 28 '09 at 23:05
  • 2
    Poor people with their .museum TLD. – BadPirate Sep 03 '10 at 17:53
3

Digging up the dirt, but I just stumbled upon SHEmailValidator which does a perfect job and has a nice interface.

Cyrille
  • 25,014
  • 12
  • 67
  • 90
  • This question was specific to iOS 2.0 which did not have NSPredicate or a whole host of other things that are being used in that library. – Marcus S. Zarra Nov 15 '13 at 19:22
  • 1
    I know, but I landed here first while searching "ios email validation". Maybe some future me will perform the same search and land here and it'll save him some time. – Cyrille Nov 16 '13 at 18:19
1

Many web sites provide RegExes but you'd do well to learn and understand them as well as verify that what you want it to do meets your needs within the official RFC for email address formats.

For learning RegEx, interpreted languages can be a great simplifier and testbed. Rubular is built on Ruby, but is a good quick way to test and verify: http://www.rubular.com/

Beyond that, buy the latest edition of the O'Reilly book Mastering Regular Expressions. You'll want to spend the time to understand the first 3 or 4 chapters. Everything after that will be building expertise on highly optimized RegEx usage.

Often a series of smaller, easier to manage RegExes are easier to maintain and debug.

user656483
  • 21
  • 1
0

Here is an extension of String that validates an email in Swift.

extension String {

    func isValidEmail() -> Bool {
        let stricterFilter = false
        let stricterFilterString = "^[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$"
        let laxString = "^.+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$"
        let emailRegex = stricterFilter ? stricterFilterString : laxString
        let emailTest = NSPredicate(format: "SELF MATCHES %@", emailRegex)
        return emailTest.evaluate(with: self)
    }
}

Copied from the answer to: Check that an email address is valid on iOS

Community
  • 1
  • 1
InnisBrendan
  • 2,079
  • 2
  • 19
  • 21
-2

You shouldn't try to use regex to validate an email. With ever changing TLDs, your validator is either incomplete or inaccurate. Instead, you should leverage Apple's NSDataDetector libraries which will take a string and try to see if there are any known data fields (emails, addresses, dates, etc). Apple's SDK will do the heavy lifting of keeping up to date with TLDs and you can piggyback off of their efforts!! :)

Plus, if iMessage (or any other text field) doesn't think it's an email, should you consider an email?

I put this function in a NSString category, so the string you're testing is self.

- (BOOL)isValidEmail {
    // Trim whitespace first
    NSString *trimmedText = [self stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
    if (self && self.length > 0) return NO;

    NSError *error = nil;
    NSDataDetector *dataDetector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink error:&error];
    if (!dataDetector) return NO;

    // This string is a valid email only if iOS detects a mailto link out of the full string
    NSArray<NSTextCheckingResult *> *allMatches = [dataDetector matchesInString:trimmedText options:kNilOptions range:NSMakeRange(0, trimmedText.length)];
    if (error) return NO;
    return (allMatches.count == 1 && [[[allMatches.firstObject URL] absoluteString] isEqual:[NSString stringWithFormat:@"mailto:%@", self]]);
}

or as a swift String extension

extension String {
    func isValidEmail() -> Bool {
        let trimmed = self.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty, let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
            return false
        }
        let allMatches = dataDetector.matches(in: trimmed, options: [], range: NSMakeRange(0, trimmed.characters.count))

        return allMatches.count == 1 && allMatches.first?.url?.absoluteString == "mailto:\(trimmed)"
    }
}
Mr. T
  • 12,795
  • 5
  • 39
  • 47
-7
// Method Call
NSString *email = @"Your Email string..";

BOOL temp = [self validateEmail:email];

if(temp)
{
// Valid
}
else
{
// Not Valid
}
// Method description

- (BOOL) validateEmail: (NSString *) email {
    NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
    BOOL isValid = [emailTest evaluateWithObject:email];
    return isValid;
}
Gaurav Gilani
  • 1,584
  • 14
  • 18
  • 3
    This thread/question is for iOS 2. `NSPredicate` did not exist in iOS 2; it was not added until iOS 3. – Marcus S. Zarra May 19 '14 at 19:48
  • 3
    I replied because your answer is wrong. The question is "how do you do X on iOS Y" and you answered with a framework that does not exist on that version of iOS. – Marcus S. Zarra May 21 '14 at 15:17