This is what we use. Nearly all users have email addresses with English characters. But we had already few exceptions, I believe with some accent characters used in Italian. So we needed already the possibility to allow exceptional special characters where we normally want to treat them as errors.
method VerifyEmailRecipient (cEMailRecipientValue, coptions) as usual clipper
local cchl, cch, c as string
local a as array
local n, ich, ipart as dword
local cerror := "" as string
c := cEMailRecipientValue
local cemailallowedcharacters := ".@!#$%&'*+-/=?^_`{|}~äöüàèé" as string
// zum leichten Hinzufügen von Extrazeichen über Login-Makro
// Unter Umständen ist sinnvoll, diese in der obenstehenden Zeile fest hinzuzufügen
cemailallowedcharacters += lower(getglobal (#emailallowedcharacters, ""))
// The local-part of the email address may use any of these ASCII characters:
// uppercase and lowercase Latin letters A to Z and a to z;
// digits 0 to 9;
// special characters !#$%&'*+-/=?^_`{|}~;
// dot ., provided that it is not the first or last character unless quoted, and provided also that it does not appear consecutively unless quoted (e.g. John..Doe@example.com is not allowed but "John..Doe"@example.com is allowed);
// space and "(),:;<>@[] characters are allowed with restrictions (they are only allowed inside a quoted string, as described in the paragraph below, and in addition, a backslash or double-quote must be preceded by a backslash);
// comments are allowed with parentheses at either end of the local-part; e.g. john.smith(comment)@example.com and (comment)
john.smith@example.com are both equivalent to
john.smith@example.com.
a := string2array(alltrim(c), ";")
for ipart := 1 upto alen(a)
c :=a[ipart]
if !Empty(c)
for ich := 1 upto slen(c)
cch := charpos(c, ich)
cchl := lower(cch)
if !Between (cchl, "0", "9") .and. !Between (cchl, "a", "z") .and. !instr(cchl, cemailallowedcharacters)
cerror := Msg(20018/*ID_NICHT_ERLAUBTE_ZEICHEN*/) +": " + cch
if !(cch==cchl)
cerror += " ("+cchl+")"
endif
endif
if !Empty(cerror)
exit
endif
next
n := occurs("@", c)
if n == 0
cerror := Msg(51758/*ID_DAS_ZEICHEN_PROZ1_WURDE_NICHT_GEFUNDEN*/, "@")
elseif n > 1
cerror := Msg(51759/*ID_DAS_ZEICHEN_PROZ1_WURDE_MEHRMALS_VERWENDET*/, "@")
endif
if instr("..", c)
cerror := Msg(51759/*ID_DAS_ZEICHEN_PROZ1_WURDE_MEHRMALS_VERWENDET*/, ".")
endif
if !Empty(cerror)
exit
endif
endif
next
if !Empty(cerror)
cerror := Msg(51760/*ID_DIE_E_MAIL_ADRESSE_ENTSPRICHT_NICHT_UEBLICHEN_R*/)+": " + cEMailRecipientValue+" - " + cerror
endif
return cerror