Quel serait le bon type de données pour stocker les adresses e-mail dans PostgreSQL?
Je peux utiliser varchar
(ou même text
), mais je me demande s'il existe un type de données plus spécifique pour les e-mails.
DOMAIN
s personnaliséJe ne pense pas que l'utilisation de citext
(insensible à la casse) soit suffisante[1]. En utilisant PostgreSQL, nous pouvons créer un domaine personnalisé qui est essentiellement des contraintes définies sur un type. Nous pouvons créer un domaine par exemple sur le type citext
, ou sur text
.
type=email
specActuellement, la réponse la plus correcte à la question qu'est-ce qu'une adresse e-mail est spécifiée dans RFC5322 . Cette spécification est incroyablement complexe[2], à tel point que tout le casse. HTML5 contient une spécification différente pour le courrier électronique ,
Cette exigence est une violation délibérée de la RFC 5322, qui définit une syntaxe pour les adresses électroniques qui est simultanément trop stricte (avant le caractère "@"), trop vague (après le "@" ) et trop laxiste (autorisant les commentaires, les espaces et les chaînes entre guillemets d'une manière inconnue de la plupart des utilisateurs) pour être d'une utilité pratique ici. [...] Le code JavaScript et Perl suivant -une expression régulière compatible est une implémentation de la définition ci-dessus.
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
C'est probablement ce que vous voulez, et si c'est assez bon pour HTML5, c'est probablement assez bon pour vous. Nous pouvons l'utiliser directement dans PostgreSQL. J'utilise également citext
ici (ce qui signifie techniquement que vous pouvez simplement regex un peu visuellement en supprimant les majuscules ou les minuscules).
CREATE EXTENSION citext;
CREATE DOMAIN email AS citext
CHECK ( value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$' );
Maintenant vous pouvez faire ...
SELECT '[email protected]'::email;
Mais non
SELECT 'asdf@foob,,ar.com'::email;
SELECT 'asd@[email protected]'::email;
Parce que les deux reviennent
ERROR: value for domain email violates check constraint "email_check"
Parce que c'est aussi basé sur citext
SELECT '[email protected]'::email = '[email protected]';
renvoie true par défaut.
plperlu
/ Email::Valid
Comme note importante, il existe une méthode plus correcte de faire cela qui est beaucoup plus complexe en utilisant plperlu
. Si vous avez besoin de ce niveau d'exactitude, vous faites pas voulez citext
. Email::Valid
peut même vérifier si le domaine a un enregistrement MX (exemple dans les documents de Email :: Valid)! Tout d'abord, ajoutez plperlu (nécessite un superutilisateur).
CREATE EXTENSION plperlu;
Alors créez la fonction , notez que nous marquons en tant que IMMUTABLE
:
CREATE FUNCTION valid_email(text)
RETURNS boolean
LANGUAGE plperlu
IMMUTABLE LEAKPROOF STRICT AS
$$
use Email::Valid;
my $email = shift;
Email::Valid->address($email) or die "Invalid email address: $email\n";
return 'true';
$$;
Alors créez le domaine ,
CREATE DOMAIN validemail AS text NOT NULL
CONSTRAINT validemail_check CHECK (valid_email(VALUE));
citext
est techniquement incorrecte. SMTP définit local-part
comme étant sensible à la casse. Mais, encore une fois, c'est un cas de la spécification étant stupide. Il contient ses propres crises d'identité. La spécification dit local-part
(la partie avant le @
) "PEUT être sensible à la casse" ... "DOIT ÊTRE traité comme sensible à la casse" ... et pourtant "exploiter la sensibilité à la casse des parties locales de la boîte aux lettres entrave l'interopérabilité et est déconseillé."Aucune de ces expressions régulières n'applique de limites de longueur à l'adresse e-mail globale ou à la partie locale ou aux noms de domaine. RFC 5322 ne spécifie aucune limitation de longueur. Celles-ci découlent de limitations dans d'autres protocoles comme le protocole SMTP pour l'envoi de courriers électroniques. La RFC 1035 stipule que les domaines doivent contenir 63 caractères ou moins, mais ne les inclut pas dans sa spécification de syntaxe. La raison en est qu'un véritable langage régulier ne peut pas appliquer une limite de longueur et interdire les tirets consécutifs à le même temps.
J'utilise toujours CITEXT
pour les e-mails, car une adresse e-mail est (en pratique) insensible à la casse , c'est-à-dire que [email protected] est identique à [email protected].
Il est également plus facile de configurer un index unique pour éviter les doublons, par rapport au texte:
-- citext
CREATE TABLE address (
id serial primary key,
email citext UNIQUE,
other_stuff json
);
-- text
CREATE TABLE address (
id serial primary key,
email text,
other_stuff json
);
CREATE UNIQUE INDEX ON address ((lower(email)));
La comparaison des e-mails est également plus facile et moins sujette aux erreurs:
SELECT * FROM address WHERE email = '[email protected]';
comparé à:
SELECT * FROM address WHERE lower(email) = lower('[email protected]');
CITEXT
est un type défini dans un module d'extension standard nommé "citext" , et disponible en tapant:
CREATE EXTENSION citext;
P.S. text
et varchar
sont pratiquement les mêmes dans Postgres et il n'y a pas de pénalité pour utiliser text
comme on peut s'y attendre. Cochez cette réponse: Différence entre le texte et varchar
J'utilise toujours varchar(254)
car une adresse e-mail ne doit pas dépasser 254 caractères.
Voir https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address
Postgresql n'a pas de type intégré pour les adresses e-mail, bien que j'aie rencontré un type de données contribué.
En outre, vous souhaiterez peut-être ajouter un déclencheur ou une telle logique pour normaliser les adresses e-mail au cas où vous souhaiteriez y ajouter une clé unique.
En particulier, la partie domain
de l'adresse e-mail (qui est de la forme local-part
@ domain
ne respecte pas la casse tandis que local-part
doit être traité comme sensible à la casse. Voir http://tools.ietf.org/html/rfc5321#section-2.4
Si vous souhaitez stocker des noms et des adresses e-mail sous la forme "Joe Bloggs" <[email protected]>
, auquel cas vous avez besoin d'une chaîne de plus de 254 caractères et vous ne pourrez pas utiliser de manière significative une contrainte unique. Je ne ferais pas cela et suggère de stocker le nom et l'adresse e-mail séparément. De jolies adresses d'impression dans ce format sont toujours possibles dans votre couche de présentation.
Vous pourriez être intéressé par l'utilisation d'une vérification CONTRAINTE (peut-être plus facile, mais pourrait rejeter plus que vous ne le souhaiteriez, ou vous utilisez une FONCTION, discutée - ici et ici . Fondamentalement, il s'agit de compromis entre spécificité et facilité de mise en œuvre. Sujet intéressant cependant. PostgreSQL a même un type d'adresse IP natif, mais il existe un projet sur pgfoundry pour un type de données e-mail ici . Cependant, le meilleur que j'ai trouvé à ce sujet est un e-mail domaine . Le domaine est meilleur qu'une contrainte de vérification car si vous le changez, vous n'avez de le faire une fois dans la définition de domaine et de ne pas suivre les traces des tables parent-enfant en changeant toutes vos contraintes de vérification. Les domaines sont vraiment cool - un peu comme les types de données, mais plus simples à implémenter. Je les ai utilisés dans Firebird - Oracle n'a même pas leur!