45

How can I create a constraint to use a regular expression in postgres?

4 Answers 4

74
CREATE TABLE emails (
    email varchar
    CONSTRAINT proper_email CHECK (email ~* '^[A-Za-z0-9._+%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$')
);

(regex may be incomplete, you can search for regexp for email matching all over the web and pick the one you like best).

Sign up to request clarification or add additional context in comments.

5 Comments

How can we make this work with ALTER command with both ADD CONSTRAINT and MODIFY varient?
What do you mean both add and modify? With add you do something like ALTER TABLE emails ADD CONSTRAINT proper_email CHECK .... I believe. Something similar with modify, just check the docs. Or, like they say here - what have you tried?
That regexp excludes addresses that contain a + in the username which is allowed by the email specs.
@smithkm, right, I said it may be incomplete back in 2011 and now we know I was right ;-)
@smithkm I've added the + in the regexp :)
27

I recommend using an existing email address parsing module instead of making up your own pattern matching. For example:

CREATE OR REPLACE FUNCTION check_email(email text) RETURNS bool
LANGUAGE plperlu
AS $$
use Email::Address;

my @addresses = Email::Address->parse($_[0]);
return scalar(@addresses) > 0 ? 1 : 0;
$$;

CREATE TABLE emails (
    email varchar
    CONSTRAINT proper_email CHECK (check_email(email))
);

2 Comments

I would say this is the right way but Amazon doesn't support it (perl) in RDS :-(. Maybe one day.
+1 as I think this is the right way but I prefer a function name like valid_email() as it's then obvious what the return values of true and false mean
23

You can also create a domain and use it as a type when defining table columns, e.g.

CREATE DOMAIN email AS TEXT CHECK (VALUE ~* '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$');

CREATE TABLE emails (
    email email
);

This way you will not need to redefine the regex every time an email containing columns is used in the database.

Comments

1

A better pattern, taken from the OWASP regexp validation library at https://owasp.org/www-community/OWASP_Validation_Regex_Repository is :

/^[a-zA-Z0-9_+&-]+(?:.[a-zA-Z0-9_+&-]+)*@(?:[a-zA-Z0-9-]+.)+[a-zA-Z]{2,7}$/

But this is quite limiting. It does not support comments or quoted names, nor does it support email to an IP address such as name@[10.99.22.4] which is valid. Also valid are UUCP email addresses and a host of others.

https://emailregex.com/ Suggest the following regexp:

(?:[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])+)\])

Though I notice there are no anchors (^$) for this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.