diff --git a/class.oauth.php b/class.oauth.php new file mode 100644 index 000000000..3d3df2a63 --- /dev/null +++ b/class.oauth.php @@ -0,0 +1,49 @@ +oauthClientId = $ClientId; + $this->oauthClientSecret = $ClientSecret; + $this->oauthRefreshToken = $RefreshToken; + $this->oauthUserEmail = $UserEmail; + } + + private function getProvider() { + return new League\OAuth2\Client\Provider\Google([ + 'clientId' => $this->oauthClientId, + 'clientSecret' => $this->oauthClientSecret + ]); + } + + private function getGrant(){ + return new \League\OAuth2\Client\Grant\RefreshToken(); + } + + private function getToken(){ + $provider = $this->getProvider(); + $grant = $this->getGrant(); + return $provider->getAccessToken($grant, ['refresh_token' => $this->oauthRefreshToken]); + } + + public function getOauth64(){ + $token = $this->getToken(); + echo $this->oauthUserEmail; + return base64_encode("user=" . $this->oauthUserEmail . "\001auth=Bearer " . $token . "\001\001"); + } + + +} +?> + diff --git a/class.phpmailer.php b/class.phpmailer.php index 09bbd553c..a43a3384f 100644 --- a/class.phpmailer.php +++ b/class.phpmailer.php @@ -443,7 +443,18 @@ class PHPMailer * @type string */ public $XMailer = ''; - + + /** + * Only For XOAUTH - Google + * Options: An empty string for PHPMailer default, Enter the email used to get access token + * @type string + */ +// public $UserEmail = ''; +// public $RefreshToken = ''; +// public $ClientId = ''; +// public $ClientSecret = ''; + + /** * An instance of the SMTP sender class. * @type SMTP @@ -1317,7 +1328,7 @@ public function smtpConnect($options = array()) if (is_null($this->smtp)) { $this->smtp = $this->getSMTPInstance(); } - + // Already connected? if ($this->smtp->connected()) { return true; @@ -1392,10 +1403,10 @@ public function smtpConnect($options = array()) } if ($this->SMTPAuth) { if (!$this->smtp->authenticate( - $this->Username, - $this->Password, - $this->AuthType, - $this->Realm, + $this->Username, + $this->Password, + $this->AuthType, + $this->Realm, $this->Workstation ) ) { diff --git a/class.phpmailer54.php b/class.phpmailer54.php new file mode 100644 index 000000000..f771ec333 --- /dev/null +++ b/class.phpmailer54.php @@ -0,0 +1,163 @@ +oauth)) { + $this->oauth = new OAuth($this->oauthUserEmail, + $this->oauthClientSecret, + $this->oauthClientId, + $this->oauthRefreshToken + ); + } + return $this->oauth; + } + + public function smtpConnect($options = array()) + { + if (is_null($this->smtp)) { + $this->smtp = $this->getSMTPInstance(); + } + + if (is_null($this->oauth)) { + $this->oauth = $this->getOAUTHInstance(); + } + + // Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = array(); + if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) { + // Not a valid host entry + continue; + } + // $hostinfo[2]: optional ssl or tls prefix + // $hostinfo[3]: the hostname + // $hostinfo[4]: optional port number + // The host string prefix can temporarily override the current setting for SMTPSecure + // If it's not specified, the default value is used + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = ($this->SMTPSecure == 'tls'); + if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = 'ssl'; + } elseif ($hostinfo[2] == 'tls') { + $tls = true; + // tls doesn't use a prefix + $secure = 'tls'; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA1'); + if ('tls' === $secure or 'ssl' === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[3]; + $port = $this->Port; + $tport = (integer)$hostinfo[4]; + if ($tport > 0 and $tport < 65536) { + $port = $tport; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + // * it's not disabled + // * we have openssl extension + // * we are not already using SSL + // * the server offers STARTTLS + if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new phpmailerException($this->lang('connect_host')); + } + // We must resend HELO after tls negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth) { + if (!$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->Realm, + $this->Workstation, + $this->oauth + ) + ) { + throw new phpmailerException($this->lang('authenticate')); + } + } + return true; + } catch (phpmailerException $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + // We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + // If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + // As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions and !is_null($lastexception)) { + throw $lastexception; + } + return false; + } + +} + +?> \ No newline at end of file diff --git a/class.smtp.php b/class.smtp.php index b2dfdc189..3d0a525cd 100644 --- a/class.smtp.php +++ b/class.smtp.php @@ -364,7 +364,8 @@ public function authenticate( $password, $authtype = null, $realm = '', - $workstation = '' + $workstation = '', + $OAuth = null ) { if (!$this->server_caps) { $this->setError('Authentication is not allowed before HELO/EHLO'); @@ -436,6 +437,19 @@ public function authenticate( return false; } break; + case 'XOAUTH': + //If the OAuth Instance is not set. Can be a case when PHPMailer is used + //instead of PHPMailer54 + if(is_null($OAuth)) + return false; + + $oauth = $OAuth->getOauth64(); + + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { + return false; + } + break; case 'NTLM': /* * ntlm_sasl_client.php diff --git a/composer.json b/composer.json index 53d29e8e5..2d7205967 100644 --- a/composer.json +++ b/composer.json @@ -1,39 +1,43 @@ { - "name": "phpmailer/phpmailer", - "type": "library", - "description": "PHPMailer is a full-featured email creation and transfer class for PHP", - "authors": [ +"name": "phpmailer/phpmailer", + "type": "library", + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "authors": [ { - "name": "Marcus Bointon", - "email": "phpmailer@synchromedia.co.uk" + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" }, { - "name": "Jim Jagielski", - "email": "jimjag@gmail.com" + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" }, { - "name": "Andy Prevost", - "email": "codeworxtech@users.sourceforge.net" + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" }, { - "name": "Brent R. Matzelle" + "name": "Brent R. Matzelle" } - ], - "require": { - "php": ">=5.0.0" - }, - "require-dev": { + ], + "require": { + "php": ">=5.0.0", + "league/oauth2-client": "0.10.*", + "guzzle/guzzle": "~3.7" + }, + "require-dev": { "phpdocumentor/phpdocumentor": "*", - "phpunit/phpunit": "4.3.*" - }, - "autoload": { + "phpunit/phpunit": "4.3.*" + }, + "autoload": { "classmap": [ - "class.phpmailer.php", - "class.smtp.php", - "class.pop3.php", - "extras/EasyPeasyICS.php", - "extras/ntlm_sasl_client.php" + "class.phpmailer.php", + "class.phpmailer54.php", + "class.oauth.php", + "class.smtp.php", + "class.pop3.php", + "extras/EasyPeasyICS.php", + "extras/ntlm_sasl_client.php" ] - }, - "license": "LGPL-2.1" -} \ No newline at end of file + }, + "license": "LGPL-2.1" + } diff --git a/examples/gmail_xoauth.php b/examples/gmail_xoauth.php new file mode 100644 index 000000000..f6c659e46 --- /dev/null +++ b/examples/gmail_xoauth.php @@ -0,0 +1,84 @@ +isSMTP(); + +//Enable SMTP debugging +// 0 = off (for production use) +// 1 = client messages +// 2 = client and server messages +$mail->SMTPDebug = 2; + +//Ask for HTML-friendly debug output +$mail->Debugoutput = 'html'; + +//Set the hostname of the mail server +$mail->Host = 'smtp.gmail.com'; + +//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission +$mail->Port = 587; + +//Set the encryption system to use - ssl (deprecated) or tls +$mail->SMTPSecure = 'tls'; + +//Whether to use SMTP authentication +$mail->SMTPAuth = true; + +//Set AuthTYpe +$mail->AuthType = 'XOAUTH'; + +//UserEmail to use for SMTP authentication - Use the same Email used in Google Developer Console +$mail->oauthUserEmail = "from@example.com"; + +//Obtained From Google Developer Console +$mail->oauthClientId = "RANDOMCHARS----n2.apps.googleusercontent.com"; + +//Obtained From Google Developer Console +$mail->oauthClientSecret = "RANDOMCHARS----yjPcRtvP"; + +//Obtained By running get_oauth_token.php after setting up APP in Google Developer Console. +//Set Redirect URI in Developer Console as [https/http]:////get_oauth_token.php +// eg: http://localhost/phpmail/get_oauth_token.php +$mail->oauthRefreshToken = "RANDOMCHARS----uwFAmhMgMEudVrK5jSpoR30zcRFq6"; + +$mail->setFrom('from@example.com', 'First Last'); + +//Set an alternative reply-to address +$mail->addReplyTo('replyto@example.com', 'First Last'); + +//Set who the message is to be sent to +$mail->addAddress('whoto@example.com', 'John Doe'); + +//Set the subject line +$mail->Subject = 'PHPMailer GMail SMTP test'; + +//Read an HTML message body from an external file, convert referenced images to embedded, +//convert HTML into a basic plain-text alternative body +$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); + +//Replace the plain text body with one created manually +$mail->AltBody = 'This is a plain-text message body'; + +//Attach an image file +$mail->addAttachment('images/phpmailer_mini.png'); + +//send the message, check for errors +if (!$mail->send()) { + echo "Mailer Error: " . $mail->ErrorInfo; +} else { + echo "Message sent!"; +} +?> diff --git a/examples/gmail_xoauth.phps b/examples/gmail_xoauth.phps new file mode 100644 index 000000000..1a2c1e7d7 --- /dev/null +++ b/examples/gmail_xoauth.phps @@ -0,0 +1,84 @@ +isSMTP(); + +//Enable SMTP debugging +// 0 = off (for production use) +// 1 = client messages +// 2 = client and server messages +$mail->SMTPDebug = 0; + +//Ask for HTML-friendly debug output +$mail->Debugoutput = 'html'; + +//Set the hostname of the mail server +$mail->Host = 'smtp.gmail.com'; + +//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission +$mail->Port = 587; + +//Set the encryption system to use - ssl (deprecated) or tls +$mail->SMTPSecure = 'tls'; + +//Whether to use SMTP authentication +$mail->SMTPAuth = true; + +//Set AuthTYpe +$mail->AuthType = 'XOAUTH'; + +//UserEmail to use for SMTP authentication - Use the same Email used in Google Developer Console +$mail->UserEmail = "someone@gmail.com"; + +//Obtained From Google Developer Console +$mail->ClientId = "RANDOMCHARS-----duv1n2.apps.googleusercontent.com"; + +//Obtained From Google Developer Console +$mail->ClientSecret = "RANDOMCHARS-----lGyjPcRtvP"; + +//Obtained By running get_oauth_token.php after setting up APP in Google Developer Console. +//Set Redirect URI in Developer Console as [https/http]:////get_oauth_token.php +// eg: http://localhost/phpmail/get_oauth_token.php +$mail->RefreshToken = "RANDOMCHARS-----DWxgOvPT003r-yFUV49TQYag7_Aod7y0"; + +//Set who the message is to be sent from +$mail->setFrom('from@example.com', 'First Last'); + +//Set an alternative reply-to address +$mail->addReplyTo('replyto@example.com', 'First Last'); + +//Set who the message is to be sent to +$mail->addAddress('whoto@example.com', 'John Doe'); + +//Set the subject line +$mail->Subject = 'PHPMailer GMail SMTP test'; + +//Read an HTML message body from an external file, convert referenced images to embedded, +//convert HTML into a basic plain-text alternative body +$mail->msgHTML(file_get_contents('contents.html'), dirname(__FILE__)); + +//Replace the plain text body with one created manually +$mail->AltBody = 'This is a plain-text message body'; + +//Attach an image file +$mail->addAttachment('images/phpmailer_mini.png'); + +//send the message, check for errors +if (!$mail->send()) { + echo "Mailer Error: " . $mail->ErrorInfo; +} else { + echo "Message sent!"; +} +?> \ No newline at end of file diff --git a/get_oauth_token.php b/get_oauth_token.php new file mode 100644 index 000000000..77016808e --- /dev/null +++ b/get_oauth_token.php @@ -0,0 +1,48 @@ +//get_oauth_token.php +// eg: http://localhost/phpmail/get_oauth_token.php +$provider = new League\OAuth2\Client\Provider\Google ([ + 'clientId' => 'RANDOMCHARS----p05gduv1n2.apps.googleusercontent.com', + 'clientSecret' => 'RANDOMCHARS----CWufYlGyjPcRtvP', + 'redirectUri' => $redirectUri, + 'scopes' => ['https://mail.google.com/'], + 'accessType' => 'offline' + ]); + +if (!isset($_GET['code'])) { + + // If we don't have an authorization code then get one + $authUrl = $provider->getAuthorizationUrl(); + $_SESSION['oauth2state'] = $provider->state; + header('Location: ' . $authUrl); + exit; +// Check given state against previously stored one to mitigate CSRF attack +} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { + + unset($_SESSION['oauth2state']); + exit('Invalid state'); +} else { + + $provider->accessType = 'offline'; + // Try to get an access token (using the authorization code grant) + $token = $provider->getAccessToken('authorization_code', [ + 'code' => $_GET['code'] + ]); + + +// Use this to interact with an API on the users behalf +// echo $token->accessToken.'
'; + + // Use this to get a new access token if the old one expires + echo 'Refresh Token: '.$token->refreshToken; + +// Unix timestamp of when the token will expire, and need refreshing +// echo $token->expires; +} +?> \ No newline at end of file