14

I'm currently building a Slack bot using Laravel, and one of the features is that it can receive an email address and send a message to it.

The issue is that email addresses (e.g bob@example.com) come through as <mailto:bob@example.com|bob@example.com> from Slack.

I currently have a function that retrieves the email from this:

public function getEmail($string)
{
    $pattern = '/[a-z0-9_\-\+]+@[a-z0-9\-]+\.([a-z]{2,3})(?:\.[a-z]{2})?/i';
    preg_match_all($pattern, $string, $matches);
    $matches = array_filter($matches);

    return $matches[0][0];
}

This seemed to be working fine with email addresses like bob@example.com, however it seems to fail when working with email addresses like bob.jones@example.com (which would come through as <mailto:bob.jones@example.com|bob.jones@example.com>. In these cases, the function is returning jones@example.com as the email address.

I'm not great with regex, but is there something else I could use/change in my pattern, or a better way to fetch the email address from the string provided by Slack?

Kurt Van den Branden
  • 11,995
  • 10
  • 76
  • 85
James
  • 15,754
  • 12
  • 73
  • 91

3 Answers3

10

Could always take regex out of the equation if you know that's always the format it'll be in:

$testString = '<mailto:bob@example.com|bob@example.com>';

$testString = str_replace(['<mailto:', '>'], '', $testString);

$addresses = explode('|', $testString);

echo $addresses[0];
bcmcfc
  • 25,966
  • 29
  • 109
  • 181
  • 2
    And just add below for validation: `foreach ($addresses as $value) { if (filter_var($value, FILTER_VALIDATE_EMAIL)) { echo "Valid Email: " . $value . "
    "; } }`
    – Kitson88 Nov 19 '16 at 11:32
  • 4
    This, combined with a small tweak from @Kitson88 worked perfectly. Thanks to you both! – James Nov 19 '16 at 11:38
  • @bcmcfc, It seems you master laravel. I need you help. Look here : http://stackoverflow.com/questions/41887504/how-to-solve-missing-argument-1-for-app-repositories-favoriterepositorydelete/41887543 – moses toh Jan 27 '17 at 06:44
4

This method will do the job and you avoid to have regular expressions. and make sure the email being returned is a real email address by validating it with php functions.

function getEmailAddress($string) 
{
    $string = trim($string, '<>');
    $args = explode('|', $string);
    foreach ($args as $_ => $val) {
        if(filter_var($val, FILTER_VALIDATE_EMAIL) !== false) {
            return $val;
        }
    }

    return null;    
}

echo getEmailAddress('<mailto:bob@example.com|bob@example.com>');

Output

bob@example.com
Jorge Y. C. Rodriguez
  • 3,394
  • 5
  • 38
  • 61
0

You know the strings containing the e-mail address will always be of the form <mailto:bob@example.com|bob@example.com>, so use that. Specifically, you know the string will start with <mailto:, will contain a |, and will end with >.

An added difficulty though, is that the local part of an e-mail address may contain a pipe character as well, but the domain may not; see the following question.
What characters are allowed in an email address?

public function getEmail($string)
{
    $pattern = '/^<mailto:([^@]+@[^|]+)|(.*)>$/i';
    preg_match_all($pattern, $string, $matches);
    $matches = array_filter($matches);
    return $matches[1][0];
}

This matches the full line from beginning to end, but we capture the e-mail address within the first set of parentheses. $matches[1] contains all matches from the first capturing parentheses. You could use preg_match instead, since you're not looking for all matches, just the first one.

Community
  • 1
  • 1
SQB
  • 3,926
  • 2
  • 28
  • 49
  • +1 never knew emails could contain a pipe. Seems crazy though, imagine trying to explain to someone over the phone that your email has a pipe character. It's hard enough getting people to comprehend a personal domain sometimes! Out of curiosity I just tested gmail and they're only supporting a subset of the spec: "Please use only letters (a-z), numbers, and periods." – bcmcfc Nov 19 '16 at 14:05
  • @bcmcfc each domain can set its own rules, as long as they don't violate the spec. But they don't have to implement the full spec. In other words, GMail doesn't have to allow `bc|mc|fc@gmail.com`, but they _should_ allow to send e-mail to `{bc|mc|fc}$@someotherdomain.com`. – SQB Nov 19 '16 at 14:17
  • @SQB, It seems you master laravel. I need you help. Look here : http://stackoverflow.com/questions/41047583/how-to-add-dynamic-dropdown-list-column-on-laravel-5-3-registration – moses toh Dec 09 '16 at 03:06