A Bash script to "validate"/check the syntax of e-mail addresses


mail_syntax [--echo=[in]valid|both] [--sloppy] {mailaddress}
mail_syntax [--echo=[in]valid|both] [--sloppy] -f {file}


In order to validate an e-mail address it is recommended to simply match it against a regular expression. mail_syntax essentially does the same but its name is easier to remember than the full regular expression. Moreover, it tries to be a bit more versatile.

{mailaddress} should be either a plain e-mail address or the address part must be enclosed in <> brackets. --sloppy will make the script try to find a valid address no matter what. For example, the following strings are considered valid addresses:

Foo Bar <foo@bar.not>
foo@bar.not (Foo Bar)
|foo@bar.not$                    ... though only with --sloppy

Exit code + arguments

If mail_syntax finds {mailaddress} to be invalid it returns a non-zero exit code (FALSE). What is valid and what is not is defined within the script. It's more restricted than what the RFC 2822 allows.

  --echo=invalid ... write invalid address to stdout
  --echo=valid   ... write the extracted valid address to stdout
  --echo=both    ... write the address in any case


Command line

mail_syntax foo@bar.not
mail_syntax --echo=valid "Andreas <foo@bar.not>"
mail_syntax --echo=invalid -f somepath/addresses-to-check


Example of usage within a .procmailrc recipe

* ^From: *\/[^ ].*
* !? mail_syntax "$MATCH"
{ LOG="Sender's address appears to be syntactically invalid"

Known restrictions

  1. The script is slow (compared to a single match against a regex).
  2. Valid maximum length of addresses is not checked.
  3. Local addresses are considered invalid (e.g. foo@local).
  4. IP addresses like in foobar@[] are considered invalid.
  5. Quoted local parts like in "foo"@bar.not are considered invalid.
  6. --sloppy is indeed what the name suggests.
  7. Überfoo@foobar.not is regarded valid in --sloppy mode.1)
  8. Various locale(5) settings have not been tested.


  • Use Bash regular expressions instead of sed.

Core parts

# Check if address is empty or just spaces
[[ ${ADDRESS// /} ]] || { addrinvalid ; return ; }
# Check that there is at least an @ sign and a . (dot)
[[ $ADDRESS = ${ADDRESS/@/} ]] && { addrinvalid ; return ; }
[[ $ADDRESS = ${ADDRESS/./} ]] && { addrinvalid ; return ; }
# The main check is done with _sed_ and $REGEX (see script)
echo " $ADDRESS " \
| sed -ne "
   # remove quoted text
   # retrieve address without <...> and optional ending (...)
   s/^ \($REGEX\) *\(([$VC @.]\+)\)\? *$/\1/p
   # retrieve address within <...>
   s/^[^<]*<\($REGEX\)> *$/\1/p


v0.31 2011-04-25 removed futile test for vertical whitespace + control chars
v0.30 2011-02-27 replaced [ with [[, published here


I have tested this on Debian 4 + 5 only. Use at your own risk.


This script is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License; either version 2 of the License, or (at your option) any later version.


The tar.gz includes the script, a test script and a few lists of valid and invalid address examples for individual tests.


Mostly, it will find berfoo@foobar.not.
mail_syntax.txt · Last modified: 2014-09-22 23:01 by andreas