This commit is contained in:
2025-10-20 10:02:41 +08:00
parent a4858d47fc
commit dc0a271adf
2805 changed files with 451240 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,38 @@
{
"name": "fastadminnet/fastadmin-mailer",
"type": "library",
"keywords": ["mail", "smtp"],
"description": "A very lightweight PHP SMTP mail sender",
"license": "MIT",
"homepage": "https://github.com/fastadminnet/fastadmin-mailer",
"authors": [
{
"name": "Cloud",
"email": "cloud@txthinking.com",
"homepage": "http://www.txthinking.com",
"role": "Thinker"
},
{
"name": "Matt Sowers",
"email": "msowers@erblearn.org"
}
],
"require": {
"php": ">=5.3.2",
"psr/log": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~5.0",
"monolog/monolog": "~1.13"
},
"autoload": {
"psr-4": {
"Tx\\": "src/"
}
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php"
]
}
}

View File

@@ -0,0 +1,209 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
namespace Tx;
use Psr\Log\LoggerInterface;
use \Tx\Mailer\Message;
use \Tx\Mailer\SMTP;
/**
* Class Mailer
*
* This class provides the Mailer public methods for backwards compatibility, but it is recommended
* that you use the Tx\Mailer\SMTP and Tx\Mailer\Message classes going forward
*
* @package Tx
*/
class Mailer
{
/**
* SMTP Class
* @var SMTP
*/
protected $smtp;
/**
* Mail Message
* @var Message
*/
protected $message;
/**
* construct function
* @param LoggerInterface $logger
*/
public function __construct(LoggerInterface $logger=null)
{
$this->smtp = new SMTP($logger);
$this->message = new Message();
}
/**
* set server and port
* @param string $host server
* @param int $port port
* @param string $secure ssl tls tlsv1.0 tlsv1.1 tlsv1.2
* @return $this
*/
public function setServer($host, $port, $secure=null)
{
$this->smtp->setServer($host, $port, $secure);
return $this;
}
/**
* auth with server
* @param string $username
* @param string $password
* @return $this
*/
public function setAuth($username, $password)
{
$this->smtp->setAuth($username, $password);
return $this;
}
/**
* auth oauthbearer with server
* @param string $accessToken
* @return $this
*/
public function setOAuth($accessToken)
{
$this->smtp->setOAuth($accessToken);
return $this;
}
/**
* set mail from
* @param string $name
* @param string $email
* @return $this
*/
public function setFrom($name, $email)
{
$this->message->setFrom($name, $email);
return $this;
}
/**
* set fake mail from
* @param string $name
* @param string $email
* @return $this
*/
public function setFakeFrom($name, $email)
{
$this->message->setFakeFrom($name, $email);
return $this;
}
/**
* add mail receiver
* @param string $name
* @param string $email
* @return $this
*/
public function addTo($name, $email)
{
$this->message->addTo($name, $email);
return $this;
}
/**
* add cc mail receiver
* @param string $name
* @param string $email
* @return $this
*/
public function addCc($name, $email)
{
$this->message->addCc($name, $email);
return $this;
}
/**
* add bcc mail receiver
* @param string $name
* @param string $email
* @return $this
*/
public function addBcc($name, $email)
{
$this->message->addBcc($name, $email);
return $this;
}
/**
* set mail subject
* @param string $subject
* @return $this
*/
public function setSubject($subject)
{
$this->message->setSubject($subject);
return $this;
}
/**
* set mail body
* @param string $body
* @return $this
*/
public function setBody($body)
{
$this->message->setBody($body);
return $this;
}
/**
* add mail attachment
* @param $name
* @param $path
* @return $this
*/
public function addAttachment($name, $path)
{
$this->message->addAttachment($name, $path);
return $this;
}
/**
* set mail reply-to
* @param string $name
* @param string $email
* @return $this
*/
public function setReplyTo($name, $email)
{
$this->message->setReplyTo($name, $email);
return $this;
}
/**
* Send the message...
* @return boolean
*/
public function send()
{
return $this->smtp->send($this->message);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
/**
* Created by PhpStorm.
* User: msowers
* Date: 3/30/15
* Time: 2:42 PM
*/
namespace Tx\Mailer\Exceptions;
class CodeException extends SMTPException
{
public function __construct($expected, $received, $serverMessage = null)
{
$message = "Unexpected return code - Expected: {$expected}, Got: {$received}";
if (isset($serverMessage)) {
$message .= " | " . $serverMessage;
}
parent::__construct($message);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
/**
* Created by PhpStorm.
* User: msowers
* Date: 3/30/15
* Time: 2:48 PM
*/
namespace Tx\Mailer\Exceptions;
class CryptoException extends SMTPException
{
}

View File

@@ -0,0 +1,35 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
/**
* Created by PhpStorm.
* User: msowers
* Date: 3/30/15
* Time: 1:51 PM
*/
namespace Tx\Mailer\Exceptions;
class SMTPException extends \Exception
{
public function __construct($message)
{
parent::__construct($message);
}
}

View File

@@ -0,0 +1,31 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
/**
* Created by PhpStorm.
* User: msowers
* Date: 3/30/15
* Time: 1:47 PM
*/
namespace Tx\Mailer\Exceptions;
class SendException extends SMTPException
{
}

View File

@@ -0,0 +1,456 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
namespace Tx\Mailer;
class Message
{
/**
* from name
*/
protected $fromName;
/**
* from email
*/
protected $fromEmail;
/**
* fake from name
*/
protected $fakeFromName;
/**
* fake from email
*/
protected $fakeFromEmail;
/**
* to email
*/
protected $to = array();
/**
* cc email
*/
protected $cc = array();
/**
* bcc email
*/
protected $bcc = array();
/**
* mail subject
*/
protected $subject;
/**
* mail body
*/
protected $body;
/**
*mail attachment
*/
protected $attachment = array();
/**
* message header
*/
protected $header = array();
/**
* charset
*/
protected $charset = "UTF-8";
/**
* header multipart boundaryMixed
*/
protected $boundaryMixed;
/**
* header multipart alternative
*/
protected $boundaryAlternative;
/**
* $this->CRLF
* @var string
*/
protected $CRLF = "\r\n";
/**
* Address for the reply-to header
* @var string
*/
protected $replyToName;
/**
* Address for the reply-to header
* @var string
*/
protected $replyToEmail;
public function setReplyTo($name, $email)
{
$this->replyToName = $name;
$this->replyToEmail = $email;
return $this;
}
/**
* set mail from
* @param string $name
* @param string $email
* @return $this
*/
public function setFrom($name, $email)
{
$this->fromName = $name;
$this->fromEmail = $email;
return $this;
}
/**
* set mail fake from
* @param string $name
* @param string $email
* @return $this
*/
public function setFakeFrom($name, $email)
{
$this->fakeFromName = $name;
$this->fakeFromEmail = $email;
return $this;
}
/**
* add mail receiver
* @param string $name
* @param string $email
* @return $this
*/
public function addTo($name, $email)
{
$this->to[$email] = $name;
return $this;
}
/**
* add cc mail receiver
* @param string $name
* @param string $email
* @return $this
*/
public function addCc($name, $email)
{
$this->cc[$email] = $name;
return $this;
}
/**
* add bcc mail receiver
* @param string $name
* @param string $email
* @return $this
*/
public function addBcc($name, $email)
{
$this->bcc[$email] = $name;
return $this;
}
/**
* set mail subject
* @param string $subject
* @return $this
*/
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
/**
* set mail body
* @param string $body
* @return $this
*/
public function setBody($body)
{
$this->body = $body;
return $this;
}
/**
* add mail attachment
* @param $name
* @param $path
* @return $this
*/
public function addAttachment($name, $path)
{
$this->attachment[$name] = $path;
return $this;
}
/**
* @return string
*/
public function getFromName()
{
return $this->fromName;
}
/**
* @return string
*/
public function getFromEmail()
{
return $this->fromEmail;
}
/**
* @return string
*/
public function getFakeFromName()
{
return $this->fakeFromName;
}
/**
* @return string
*/
public function getFakeFromEmail()
{
return $this->fakeFromEmail;
}
/**
* @return mixed
*/
public function getTo()
{
return $this->to;
}
/**
* @return mixed
*/
public function getCc()
{
return $this->cc;
}
/**
* @return mixed
*/
public function getBcc()
{
return $this->bcc;
}
/**
* @return mixed
*/
public function getSubject()
{
return $this->subject;
}
/**
* @return mixed
*/
public function getBody()
{
return $this->body;
}
/**
* @return array
*/
public function getAttachment()
{
return $this->attachment;
}
/**
* Create mail header
* @return $this
*/
protected function createHeader()
{
$this->header['Date'] = date('r');
$fromName = "";
$fromEmail = $this->fromEmail;
if(!empty($this->fromName)){
$fromName = sprintf("=?utf-8?B?%s?= ", base64_encode($this->fromName));
}
if(!empty($this->fakeFromEmail)){
if(!empty($this->fakeFromName)){
$fromName = sprintf("=?utf-8?B?%s?= ", base64_encode($this->fakeFromName));
}
$fromEmail = $this->fakeFromEmail;
}
$this->header['Return-Path'] = $fromEmail;
$this->header['From'] = $fromName . "<" . $fromEmail .">";
$this->header['To'] = '';
foreach ($this->to as $toEmail => $toName) {
if(!empty($toName)){
$toName = sprintf("=?utf-8?B?%s?= ", base64_encode($toName));
}
$this->header['To'] .= $toName . "<" . $toEmail . ">, ";
}
$this->header['To'] = substr($this->header['To'], 0, -2);
$this->header['Cc'] = '';
foreach ($this->cc as $toEmail => $toName) {
if(!empty($toName)){
$toName = sprintf("=?utf-8?B?%s?= ", base64_encode($toName));
}
$this->header['Cc'] .= $toName . "<" . $toEmail . ">, ";
}
$this->header['Cc'] = substr($this->header['Cc'], 0, -2);
$this->header['Bcc'] = '';
foreach ($this->bcc as $toEmail => $toName) {
if(!empty($toName)){
$toName = sprintf("=?utf-8?B?%s?= ", base64_encode($toName));
}
$this->header['Bcc'] .= $toName . "<" . $toEmail . ">, ";
}
$this->header['Bcc'] = substr($this->header['Bcc'], 0, -2);
$replyToName = "";
if(!empty($this->replyToEmail)){
if(!empty($this->replyToName)){
$replyToName = sprintf("=?utf-8?B?%s?= ", base64_encode($this->replyToName));
}
$this->header['Reply-To'] = $replyToName . "<" . $this->replyToEmail . ">";
}
if(empty($this->subject)){
$subject = '';
}else{
$subject = sprintf("=?utf-8?B?%s?= ", base64_encode($this->subject));
}
$this->header['Subject'] = $subject;
$this->header['Message-ID'] = '<' . md5(uniqid()) . $this->fromEmail . '>';
$this->header['X-Priority'] = '3';
$this->header['X-Mailer'] = 'Mailer (https://github.com/txthinking/Mailer)';
$this->header['MIME-Version'] = '1.0';
if (!empty($this->attachment)){
$this->boundaryMixed = md5(md5(time().'TxMailer').uniqid());
$this->header['Content-Type'] = "multipart/mixed; \r\n\tboundary=\"" . $this->boundaryMixed . "\"";
}
$this->boundaryAlternative = md5(md5(time().'TXMailer').uniqid());
return $this;
}
/**
* @brief createBody create body
*
* @return string
*/
protected function createBody()
{
$in = "";
$in .= "Content-Type: multipart/alternative; boundary=\"$this->boundaryAlternative\"" . $this->CRLF;
$in .= $this->CRLF;
$in .= "--" . $this->boundaryAlternative . $this->CRLF;
$in .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->CRLF;
$in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
$in .= $this->CRLF;
$in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
$in .= $this->CRLF;
$in .= "--" . $this->boundaryAlternative . $this->CRLF;
$in .= "Content-Type: text/html; charset=\"" . $this->charset ."\"" . $this->CRLF;
$in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
$in .= $this->CRLF;
$in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
$in .= $this->CRLF;
$in .= "--" . $this->boundaryAlternative . "--" . $this->CRLF;
return $in;
}
/**
* @brief createBodyWithAttachment create body with attachment
*
* @return string
*/
protected function createBodyWithAttachment()
{
$in = "";
$in .= $this->CRLF;
$in .= $this->CRLF;
$in .= '--' . $this->boundaryMixed . $this->CRLF;
$in .= "Content-Type: multipart/alternative; boundary=\"$this->boundaryAlternative\"" . $this->CRLF;
$in .= $this->CRLF;
$in .= "--" . $this->boundaryAlternative . $this->CRLF;
$in .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->CRLF;
$in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
$in .= $this->CRLF;
$in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
$in .= $this->CRLF;
$in .= "--" . $this->boundaryAlternative . $this->CRLF;
$in .= "Content-Type: text/html; charset=\"" . $this->charset ."\"" . $this->CRLF;
$in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
$in .= $this->CRLF;
$in .= chunk_split(base64_encode($this->body)) . $this->CRLF;
$in .= $this->CRLF;
$in .= "--" . $this->boundaryAlternative . "--" . $this->CRLF;
foreach ($this->attachment as $name => $path){
$in .= $this->CRLF;
$in .= '--' . $this->boundaryMixed . $this->CRLF;
$in .= "Content-Type: application/octet-stream; name=\"". $name ."\"" . $this->CRLF;
$in .= "Content-Transfer-Encoding: base64" . $this->CRLF;
$in .= "Content-Disposition: attachment; filename=\"" . $name . "\"" . $this->CRLF;
$in .= $this->CRLF;
$in .= chunk_split(base64_encode(file_get_contents($path))) . $this->CRLF;
}
$in .= $this->CRLF;
$in .= $this->CRLF;
$in .= '--' . $this->boundaryMixed . '--' . $this->CRLF;
return $in;
}
public function toString()
{
$in = '';
$this->createHeader();
foreach ($this->header as $key => $value) {
$in .= $key . ': ' . $value . $this->CRLF;
}
if (empty($this->attachment)) {
$in .= $this->createBody();
} else {
$in .= $this->createBodyWithAttachment();
}
$in .= $this->CRLF . $this->CRLF . "." . $this->CRLF;
return $in;
}
}

View File

@@ -0,0 +1,492 @@
<?php
/***************************************************\
*
* Mailer (https://github.com/txthinking/Mailer)
*
* A lightweight PHP SMTP mail sender.
* Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821
*
* Support html body, don't worry that the receiver's
* mail client can't support html, because Mailer will
* send both text/plain and text/html body, so if the
* mail client can't support html, it will display the
* text/plain body.
*
* Create Date 2012-07-25.
* Under the MIT license.
*
\***************************************************/
namespace Tx\Mailer;
use Psr\Log\LoggerInterface;
use Tx\Mailer\Exceptions\CodeException;
use Tx\Mailer\Exceptions\CryptoException;
use Tx\Mailer\Exceptions\SMTPException;
class SMTP
{
/**
* smtp socket
*/
protected $smtp;
/**
* smtp server
*/
protected $host;
/**
* smtp server port
*/
protected $port;
/**
* smtp secure ssl tls tlsv1.0 tlsv1.1 tlsv1.2
*/
protected $secure;
/**
* smtp allow insecure ssl
*/
protected $allowInsecure;
/**
* EHLO message
*/
protected $ehlo;
/**
* smtp username
*/
protected $username;
/**
* smtp password
*/
protected $password;
/**
* oauth access token
*/
protected $oauthToken;
/**
* $this->CRLF
* @var string
*/
protected $CRLF = "\r\n";
/**
* @var Message
*/
protected $message;
/**
* @var LoggerInterface - Used to make things prettier than self::$logger
*/
protected $logger;
/**
* Stack of all commands issued to SMTP
* @var array
*/
protected $commandStack = array();
/**
* Stack of all results issued to SMTP
* @var array
*/
protected $resultStack = array();
public function __construct(LoggerInterface $logger=null)
{
$this->logger = $logger;
}
/**
* set server and port
* @param string $host server
* @param int $port port
* @param string $secure ssl tls tlsv1.0 tlsv1.1 tlsv1.2
* @return $this
*/
public function setServer($host, $port, $secure=null, $allowInsecure=null)
{
$this->host = $host;
$this->port = $port;
$this->secure = $secure;
$this->allowInsecure = $allowInsecure;
if(!$this->ehlo) $this->ehlo = $host;
$this->logger && $this->logger->debug("Set: the server");
return $this;
}
/**
* auth login with server
* @param string $username
* @param string $password
* @return $this
*/
public function setAuth($username, $password)
{
$this->username = $username;
$this->password = $password;
$this->logger && $this->logger->debug("Set: the auth login");
return $this;
}
/**
* auth oauthbearer with server
* @param string $accessToken
* @return $this
*/
public function setOAuth($accessToken)
{
$this->oauthToken = $accessToken;
$this->logger && $this->logger->debug("Set: the auth oauthbearer");
return $this;
}
/**
* set the EHLO message
* @param $ehlo
* @return $this
*/
public function setEhlo($ehlo)
{
$this->ehlo = $ehlo;
return $this;
}
/**
* Send the message
*
* @param Message $message
* @return bool
* @throws CodeException
* @throws CryptoException
* @throws SMTPException
*/
public function send(Message $message)
{
$this->logger && $this->logger->debug('Set: a message will be sent');
$this->message = $message;
$this->connect()
->ehlo();
if ($this->secure === 'tls' || $this->secure === 'tlsv1.0' || $this->secure === 'tlsv1.1' | $this->secure === 'tlsv1.2') {
$this->starttls()
->ehlo();
}
if ($this->username !== null || $this->password !== null) {
$this->authLogin();
} elseif ($this->oauthToken !== null) {
$this->authOAuthBearer();
}
$this->mailFrom()
->rcptTo()
->data()
->quit();
return fclose($this->smtp);
}
/**
* connect the server
* SUCCESS 220
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function connect()
{
$this->logger && $this->logger->debug("Connecting to {$this->host} at {$this->port}");
$host = ($this->secure == 'ssl') ? 'ssl://' . $this->host : $this->host;
// Create connection
$context = null;
if ($this->allowInsecure) {
$context = stream_context_create([
'ssl' => [
'security_level' => 0,
'verify_peer' => false,
'verify_peer_name' => false
]
]);
} else {
$context = stream_context_create();
}
$this->smtp = stream_socket_client(
$host.':'.$this->port,
$error_code,
$error_message,
ini_get('default_socket_timeout'),
STREAM_CLIENT_CONNECT,
$context
);
//set block mode
// stream_set_blocking($this->smtp, 1);
if (!$this->smtp){
throw new SMTPException("Could not open SMTP Port.");
}
$code = $this->getCode();
if ($code !== '220'){
throw new CodeException('220', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP STARTTLS
* SUCCESS 220
* @return $this
* @throws CodeException
* @throws CryptoException
* @throws SMTPException
*/
protected function starttls()
{
$in = "STARTTLS" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '220'){
throw new CodeException('220', $code, array_pop($this->resultStack));
}
if ($this->secure !== 'tls' && version_compare(phpversion(), '5.6.0', '<')) {
throw new CryptoException('Crypto type expected PHP 5.6 or greater');
}
switch ($this->secure) {
case 'tlsv1.0':
$crypto_type = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
break;
case 'tlsv1.1':
$crypto_type = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
break;
case 'tlsv1.2':
$crypto_type = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
break;
default:
$crypto_type = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT |
STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT |
STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
break;
}
if(!\stream_socket_enable_crypto($this->smtp, true, $crypto_type)) {
throw new CryptoException("Start TLS failed to enable crypto");
}
return $this;
}
/**
* SMTP EHLO
* SUCCESS 250
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function ehlo()
{
$in = "EHLO " . $this->ehlo . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '250'){
throw new CodeException('250', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP AUTH LOGIN
* SUCCESS 334
* SUCCESS 334
* SUCCESS 235
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function authLogin()
{
$in = "AUTH LOGIN" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '334'){
throw new CodeException('334', $code, array_pop($this->resultStack));
}
$in = base64_encode($this->username) . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '334'){
throw new CodeException('334', $code, array_pop($this->resultStack));
}
$in = base64_encode($this->password) . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '235'){
throw new CodeException('235', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP AUTH OAUTHBEARER
* SUCCESS 235
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function authOAuthBearer()
{
$authStr = sprintf("n,a=%s,%shost=%s%sport=%s%sauth=Bearer %s%s%s",
$this->message->getFromEmail(),
chr(1),
$this->host,
chr(1),
$this->port,
chr(1),
$this->oauthToken,
chr(1),
chr(1)
);
$authStr = base64_encode($authStr);
$in = "AUTH OAUTHBEARER $authStr" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '235'){
throw new CodeException('235', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP AUTH XOAUTH2
* SUCCESS 235
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function authXOAuth2()
{
$authStr = sprintf("user=%s%sauth=Bearer %s%s%s",
$this->message->getFromEmail(),
chr(1),
$this->oauthToken,
chr(1),
chr(1)
);
$authStr = base64_encode($authStr);
$in = "AUTH XOAUTH2 $authStr" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '235'){
throw new CodeException('235', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP MAIL FROM
* SUCCESS 250
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function mailFrom()
{
$in = "MAIL FROM:<{$this->message->getFromEmail()}>" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '250') {
throw new CodeException('250', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP RCPT TO
* SUCCESS 250
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function rcptTo()
{
$to = array_merge(
$this->message->getTo(),
$this->message->getCc(),
$this->message->getBcc()
);
foreach ($to as $toEmail=>$_) {
$in = "RCPT TO:<" . $toEmail . ">" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '250') {
throw new CodeException('250', $code, array_pop($this->resultStack));
}
}
return $this;
}
/**
* SMTP DATA
* SUCCESS 354
* SUCCESS 250
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function data()
{
$in = "DATA" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '354') {
throw new CodeException('354', $code, array_pop($this->resultStack));
}
$in = $this->message->toString();
$code = $this->pushStack($in);
if ($code !== '250'){
throw new CodeException('250', $code, array_pop($this->resultStack));
}
return $this;
}
/**
* SMTP QUIT
* SUCCESS 221
* @return $this
* @throws CodeException
* @throws SMTPException
*/
protected function quit()
{
$in = "QUIT" . $this->CRLF;
$code = $this->pushStack($in);
if ($code !== '221'){
throw new CodeException('221', $code, array_pop($this->resultStack));
}
return $this;
}
protected function pushStack($string)
{
$this->commandStack[] = $string;
fputs($this->smtp, $string, strlen($string));
$this->logger && $this->logger->debug('Sent: '. $string);
return $this->getCode();
}
/**
* get smtp response code
* once time has three digital and a space
* @return string
* @throws SMTPException
*/
protected function getCode()
{
while ($str = fgets($this->smtp, 515)) {
$this->logger && $this->logger->debug("Got: ". $str);
$this->resultStack[] = $str;
$str = ltrim($str);
if(substr($str,3,1) == " ") {
$code = substr($str,0,3);
return $code;
}
}
throw new SMTPException("SMTP Server did not respond with anything I recognized");
}
}