31

Ok, there are a million regexes out there for validating an email address, but how about some basic email validation that can be integrated into a TSQL query for Sql Server 2005?

I don't want to use a CLR procedure or function. Just straight TSQL.

Has anybody tackled this already?

Eric Z Beard
  • 37,669
  • 27
  • 100
  • 145
  • possible duplicate of [Sql script to find invalid email addresses](http://stackoverflow.com/questions/801166/sql-script-to-find-invalid-email-addresses) – Victor Zakharov Jan 28 '15 at 15:28

9 Answers9

55

Very basic would be:

SELECT
  EmailAddress, 
  CASE WHEN EmailAddress LIKE '%_@_%_.__%' 
            AND EmailAddress NOT LIKE '%[any obviously invalid characters]%' 
  THEN 'Could be' 
  ELSE 'Nope' 
  END Validates
FROM 
  Table

This matches everything with an @ in the middle, preceded by at least one character, followed by at least two, a dot and at least two for the TLD.

You can write more LIKE patterns that do more specific things, but you will never be able to match everything that could be an e-mail address while not letting slip through things that are not. Even with regular expressions you have a hard time doing it right. Additionally, even matching according to the very letters of the RFC matches address constructs that will not be accepted/used by most emailing systems.

Doing this on the database level is maybe the wrong approach anyway, so a basic sanity check as indicated above may be the best you can get performance-wise, and doing it in an application will provide you with far greater flexibility.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Yeah, I already have regexes in code doing this for me, but I need to do reporting on tables with zillions of emails and come up with aggregates. – Eric Z Beard Oct 23 '08 at 14:40
  • Knowing the base data you have, you might be able to come up with something more specific and appropriate than what I suggested for a start, but you will never get it "correct" as the word is used in algorithm theory. – Tomalak Oct 23 '08 at 14:42
  • I see you added "not like '%[any obviously invalid characters]%". From what I've learned about the spec, I'm not sure there are actually any keys on the keyboard that couldn't technically be construed as valid somewhere in the address. – Eric Z Beard Oct 23 '08 at 15:18
  • That depends on your keyboard. On mine, there are 'ö', 'ä', 'ü' and 'ß', these are invalid in any case. More generally, angle brackets would for example not be allowed, and the list goes on. – Tomalak Oct 23 '08 at 15:52
  • Tomalak, the email spec RFC 5322,http://tools.ietf.org/html/rfc5322, section 3.4 allows any character inside quotes i.e. "[hello] "@domain.com. However, for practical reasons it's hard to build a validator in tsql. u need parsing tools at your disposal (lexical analysis). – Roman Nov 19 '10 at 00:09
  • 4
    This was great thank you. I just used. One error e-mail address that we run into is when it is something@q.com is valid e-mail. I think the expression should be changed from '%_@_%_.__%' to '%_@%_.__%' – JeffJak Oct 13 '11 at 14:02
20

Here's a sample function for this that's a little more detailed, I don't remember where I got this from (years ago), or if I modified it, otherwise I would include proper attribution:

CREATE FUNCTION [dbo].[fnAppEmailCheck](@email VARCHAR(255))   
--Returns true if the string is a valid email address.  
RETURNS bit  
as  
BEGIN  
     DECLARE @valid bit  
     IF @email IS NOT NULL   
          SET @email = LOWER(@email)  
          SET @valid = 0  
          IF @email like '[a-z,0-9,_,-]%@[a-z,0-9,_,-]%.[a-z][a-z]%'  
             AND LEN(@email) = LEN(dbo.fnAppStripNonEmail(@email))  
             AND @email NOT like '%@%@%'  
             AND CHARINDEX('.@',@email) = 0  
             AND CHARINDEX('..',@email) = 0  
             AND CHARINDEX(',',@email) = 0  
             AND RIGHT(@email,1) between 'a' AND 'z'  
               SET @valid=1  
     RETURN @valid  
END  
cabgef
  • 1,398
  • 3
  • 19
  • 35
  • 5
    Hi cabgef, This is best solution which u given. Could u tell me what "fnAppStripNonEmail" does? – Pankaj Pareek Oct 19 '11 at 10:47
  • 3
    I needed to add a condition `AND CHARINDEX(' ',@email) = 0` in order to check for spaces in the middle of the email address. – Wayne Bloss Sep 11 '13 at 18:06
  • I know this is an old post, but for other users benefit - This throws an error: "Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)" – user1948635 May 21 '14 at 12:36
  • Note: This function incorrectly invalidates emails that have a hyphen in it (e.g. thing-thing@gmail.com) which should be valid. – Corey Thompson Apr 27 '16 at 23:05
  • @CoreyThompson This function seems to say that 'thing-thing@gmail.com' is valid. Although it also says that thing@thing-thing.com is also valid (which as far as I understand, it is not) – Robert McKee Aug 22 '17 at 16:05
  • This seems like it wouldn't handle dots in any segment? a.b@c.d.co.uk ... should be valid I think? – Hades Oct 24 '17 at 14:08
3

Great answers! Based these recommendations I came up with a simplified function that combines the best 2 answers.

CREATE FUNCTION [dbo].[fnIsValidEmail]
(
    @email varchar(255)
)   
--Returns true if the string is a valid email address.  
RETURNS bit  
As  
BEGIN
    RETURN CASE WHEN ISNULL(@email, '') <> '' AND @email LIKE '%_@%_.__%' THEN 1 ELSE 0 END
END
James
  • 1,440
  • 14
  • 12
2

On SQL 2016 or +

CREATE FUNCTION [DBO].[F_IsEmail] (
 @EmailAddr varchar(360) -- Email address to check
)   RETURNS BIT -- 1 if @EmailAddr is a valid email address

AS BEGIN
DECLARE @AlphabetPlus VARCHAR(255)
      , @Max INT -- Length of the address
      , @Pos INT -- Position in @EmailAddr
      , @OK BIT  -- Is @EmailAddr OK
-- Check basic conditions
IF @EmailAddr IS NULL 
   OR @EmailAddr NOT LIKE '[0-9a-zA-Z]%@__%.__%' 
   OR @EmailAddr LIKE '%@%@%' 
   OR @EmailAddr LIKE '%..%' 
   OR @EmailAddr LIKE '%.@' 
   OR @EmailAddr LIKE '%@.' 
   OR @EmailAddr LIKE '%@%.-%' 
   OR @EmailAddr LIKE '%@%-.%' 
   OR @EmailAddr LIKE '%@-%' 
   OR CHARINDEX(' ',LTRIM(RTRIM(@EmailAddr))) > 0
       RETURN(0)



declare @AfterLastDot varchar(360);
declare @AfterArobase varchar(360);
declare @BeforeArobase varchar(360);
declare @HasDomainTooLong bit=0;

--Control des longueurs et autres incoherence
set @AfterLastDot=REVERSE(SUBSTRING(REVERSE(@EmailAddr),0,CHARINDEX('.',REVERSE(@EmailAddr))));
if  len(@AfterLastDot) not between 2 and 17
RETURN(0);

set @AfterArobase=REVERSE(SUBSTRING(REVERSE(@EmailAddr),0,CHARINDEX('@',REVERSE(@EmailAddr))));
if len(@AfterArobase) not between 2 and 255
RETURN(0);

select top 1 @BeforeArobase=value from  string_split(@EmailAddr, '@');
if len(@AfterArobase) not between 2 and 255
RETURN(0);

--Controle sous-domain pas plus grand que 63
select top 1 @HasDomainTooLong=1 from string_split(@AfterArobase, '.') where LEN(value)>63
if @HasDomainTooLong=1
return(0);

--Control de la partie locale en detail
SELECT @AlphabetPlus = 'abcdefghijklmnopqrstuvwxyz01234567890!#$%&‘*+-/=?^_`.{|}~'
     , @Max = LEN(@BeforeArobase)
     , @Pos = 0
     , @OK = 1


WHILE @Pos < @Max AND @OK = 1 BEGIN
    SET @Pos = @Pos + 1
    IF @AlphabetPlus NOT LIKE '%' + SUBSTRING(@BeforeArobase, @Pos, 1) + '%' 
        SET @OK = 0
END

if @OK=0
RETURN(0);

--Control de la partie domaine en detail
SELECT @AlphabetPlus = 'abcdefghijklmnopqrstuvwxyz01234567890-.'
     , @Max = LEN(@AfterArobase)
     , @Pos = 0
     , @OK = 1

WHILE @Pos < @Max AND @OK = 1 BEGIN
    SET @Pos = @Pos + 1
    IF @AlphabetPlus NOT LIKE '%' + SUBSTRING(@AfterArobase, @Pos, 1) + '%' 
        SET @OK = 0
END

if @OK=0
RETURN(0);







return(1);



END
Esperento57
  • 16,521
  • 3
  • 39
  • 45
1

FnAppStripNonEmail missing under score, need add it to the keep values

Create Function [dbo].[fnAppStripNonEmail](@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^a-z,0-9,_,@,.,-]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End
Tony Dong
  • 3,213
  • 1
  • 29
  • 32
1
CREATE FUNCTION fnIsValidEmail
(
    @email varchar(255)
)
RETURNS bit
AS
BEGIN

    DECLARE @IsValidEmail bit = 0

    IF (@email not like '%[^a-z,0-9,@,.,!,#,$,%%,&,'',*,+,--,/,=,?,^,_,`,{,|,},~]%' --First Carat ^ means Not these characters in the LIKE clause. The list is the valid email characters.
        AND @email like '%_@_%_.[a-z,0-9][a-z]%'
        AND @email NOT like '%@%@%'  
        AND @email NOT like '%..%'
        AND @email NOT like '.%'
        AND @email NOT like '%.'
        AND CHARINDEX('@', @email) <= 65
        )
    BEGIN
        SET @IsValidEmail = 1
    END

    RETURN @IsValidEmail

END
0
Create Function [dbo].[fnAppStripNonEmail](@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^a-z,0-9,@,.,-]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
0

This is the easiest way to select them.

Use this query

SELECT * FROM <TableName> WHERE [EMail] NOT LIKE '%_@__%.__%'
Alex
  • 11,115
  • 12
  • 51
  • 64
HamzeLue
  • 311
  • 3
  • 8
-2

From Tomalak's slelect

select 1
where @email not like '%[^a-z,0-9,@,.]%'
and @email like '%_@_%_.__%'
payonk
  • 5
  • 1