cwd
cwd

Reputation: 54776

Parse e-mail addresses with PHP?

Similar to this question, how could I parse e-mail addresses which are in this format,

"Bob Smith" <[email protected]>, [email protected], "John Doe"<[email protected]>

And get the a result like this:

array(
    '[email protected]'=>'Bob Smith'
    '[email protected]'=>''
    '[email protected]'=>'John Doe'
);

Upvotes: 5

Views: 13697

Answers (6)

mickmackusa
mickmackusa

Reputation: 47894

For input strings that are not properly parsed by the native function in @mario's answer, parse the substrings between delimiting commas using "branch resets" ((?|...)) and capture groups ((...)).

The branch reset ensure that (optionally occurring) names are always stored in column 1 of the matches array and that emails are always stored in column 2.

Code: (Demo)

$emails = '"Bob Smith" <[email protected]>, [email protected], "John Doe"<[email protected]>, Billy Doe<[email protected]>';

preg_match_all('/(?|(?|"([^"]+)"|([^<@]+)) ?<(.+?)>|()(.+?))(?:$|, ?)/', $emails, $matches, PREG_SET_ORDER);
var_export(
    array_column($matches, 1, 2)
);

Upvotes: 0

Victor Nazarov
Victor Nazarov

Reputation: 126

For a similar task I've used the following regex:

\s*(?:"([^"]*)"|([^,""<>]*))?\s*(?:(?:,|<|\s+|^)([^<@\s,]+@[^>@\s,]+)>?)\s*

https://regex101.com/r/Lpsjmr/1

PHP code:

$str = '"Bob Smith" <[email protected]>, [email protected], "John Doe"<[email protected]>, Billy Doe<[email protected]>';
if (preg_match_all('/\s*(?:"([^"]*)"|([^,""<>]*))?\s*(?:(?:,|<|\s+|^)([^<@\s,]+@[^>@\s,]+)>?)\s*/', $str, $matches, PREG_SET_ORDER) > 0) {
    $matches = array_map(function($x) { return [$x[1] . $x[2], $x[3]]; }, $matches);
    print_r($matches);
}

Upvotes: 1

Luke
Luke

Reputation: 14128

This should work with just about anything:

$str = '"Bob Smith" <[email protected]>, [email protected], "John Doe"<[email protected]>, Billy Doe<[email protected]>';
$emails = array();

if(preg_match_all('/\s*"?([^><,"]+)"?\s*((?:<[^><,]+>)?)\s*/', $str, $matches, PREG_SET_ORDER) > 0)
{
    foreach($matches as $m)
    {
        if(! empty($m[2]))
        {
            $emails[trim($m[2], '<>')] = $m[1];
        }
        else
        {
            $emails[$m[1]] = '';
        }
    }
}

print_r($emails);

Result:

Array
(
    [[email protected]] => Bob Smith
    [[email protected]] => 
    [[email protected]] => John Doe
    [[email protected]] => Billy Doe
)

Upvotes: 8

Kenny
Kenny

Reputation: 5410

This is a fully working piece of code below that even validates whether the email is correct or not ;)

<?php
$mails = '"Bob Smith" <[email protected]>, [email protected], "John Doe"<[email protected]>';

$records = explode(",",$mails);

foreach($records as $r){
  preg_match("#\"([\w\s]+)\"#",$r,$matches_1);
  $name = $matches_1[1];


  preg_match("/[^0-9<][A-z0-9_]+([.][A-z0-9_]+)*[@][A-z0-9_]+([.][A-z0-9_]+)*[.][A-z]{2,4}/i",$r,$matches_2);
  $email = $matches_2[0];

  echo "Name: $name <br /> Email: $email <br />";
}

?>

Upvotes: 1

mario
mario

Reputation: 145482

Well, you could use mailparse_rfc822_parse_addresses(), which does exactly that. It's a PECL extension, so it might be easier to use Mail_RFC822::parseAddressList() as mentioned in the comments.

Upvotes: 12

Tam&#225;s Pap
Tam&#225;s Pap

Reputation: 18273

  1. Explode the string by comma
  2. If valid email then store it, if NO
    1. rtrim the '>' character
    2. explode by '<'
    3. trim the string for ('"', and ' ')

Upvotes: 0

Related Questions