continue implementing mailing

This commit is contained in:
Dennis Eichhorn 2020-04-05 17:36:29 +02:00
parent c35bccd8c0
commit 2b6cd1d21b
9 changed files with 772 additions and 35 deletions

View File

@ -0,0 +1,33 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Message\Mail
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Message\Mail;
use phpOMS\Stdlib\Base\Enum;
/**
* Disposition enum.
*
* @package phpOMS\Message\Mail
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
abstract class DispositionType extends Enum
{
public const PLAIN = 'plain';
public const ALT = 'alt';
public const ATTACHMENT = 'attach';
public const INLINE = 'inline';
}

View File

@ -25,7 +25,7 @@ namespace phpOMS\Message\Mail;
* @todo Orange-Management/phpOMS#34
* Implement!!!
*/
class EmailAbstract
abstract class EmailAbstract
{
/**
* Host.
@ -33,7 +33,7 @@ class EmailAbstract
* @var string
* @since 1.0.0
*/
protected $host = '';
protected string $host = '';
/**
* Port.
@ -41,7 +41,7 @@ class EmailAbstract
* @var int
* @since 1.0.0
*/
protected $port = 25;
protected int $port = 25;
/**
* Use ssl.
@ -49,7 +49,7 @@ class EmailAbstract
* @var bool
* @since 1.0.0
*/
protected $ssl = false;
protected bool $ssl = false;
/**
* Mailbox base.
@ -57,7 +57,7 @@ class EmailAbstract
* @var string
* @since 1.0.0
*/
protected $mailbox = '';
protected string $mailbox = '';
/**
* Timeout.
@ -65,7 +65,7 @@ class EmailAbstract
* @var int
* @since 1.0.0
*/
protected $timeout = 30;
protected int $timeout = 30;
/**
* Connection.
@ -75,6 +75,30 @@ class EmailAbstract
*/
protected $con = null;
/**
* Submit type/software
*
* @var string
* @since 1.0.0
*/
protected string $submitType = SubmitType::SMTP;
/**
* Sendmail path if submit type is not smtp or mail
*
* @var string
* @since 1.0.0
*/
protected string $sendmailPath = '';
/**
* End of line
*
* @var string
* @since 1.0.0
*/
protected string $endOfLine = "\r\n";
/**
* Construct
*
@ -181,6 +205,52 @@ class EmailAbstract
return $this->con === null ? false : \imap_ping($this->con);
}
/**
* Set submit type/software
*
* @param string $submitType Submit type/software
*
* @return void
*
* @since 1.0.0
*/
public function setSubmitType(string $submitType) : void
{
$this->submitType = $submitType;
if ($this->submitType === SubmitType::SMTP || $this->submitType === SubmitType::MAIL) {
$this->endOfLine = $this->submitType === SubmitType::SMTP || !\stripos(\PHP_OS, 'WIN') === 0 ? \PHP_EOL : "\r\n";
return;
} elseif ($this->submitType === SubmitType::SENDMAIL) {
$this->endOfLine = \PHP_EOL;
$path = \ini_get('sendmail_path');
$this->sendmailPath = \stripos($path, 'sendmail') === false ? '/usr/sbin/sendmail' : $path;
} elseif ($this->submitType === SubmitType::QMAIL) {
$this->endOfLine = \PHP_EOL;
$path = \ini_get('sendmail_path');
$this->sendmailPath = \stripos($path, 'qmail') === false ? '/var/qmail/bin/qmail-inject' : $path;
}
}
/**
* Send a Mail
*
* @param Mail $mail Mail to send
*
* @return bool
*
* @since 1.0.0
*/
public function send(Mail $mail) : bool
{
if (empty($mail->getTo())) {
return false;
}
}
/**
* Get boxes.
*

View File

@ -0,0 +1,34 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Message\Mail
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Message\Mail;
use phpOMS\Stdlib\Base\Enum;
/**
* Encoding enum.
*
* @package phpOMS\Message\Mail
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
abstract class EncodingType extends Enum
{
public const E_7BIT = '7bit';
public const E_8BIT = '8bit';
public const E_BASE64 = 'base64';
public const E_BINARY = 'binary';
public const E_QUOTED = 'quoted-printable';
}

View File

@ -0,0 +1,31 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Message\Mail
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Message\Mail;
use phpOMS\Stdlib\Base\Enum;
/**
* Encryption enum.
*
* @package phpOMS\Message\Mail
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
abstract class EncryptionType extends Enum
{
public const TLS = 'tls';
public const SSL = 'ssl';
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Message\Mail
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Message\Mail;
use phpOMS\Stdlib\Base\Enum;
/**
* Calendar message types enum.
*
* @package phpOMS\Message\Mail
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
abstract class ICALMethodType extends Enum
{
public const REQUEST = 'REQUEST';
public const PUBLISH = 'PUBLISH';
public const REPLY = 'REPLY';
public const ADD = 'ADD';
public const CANCEL = 'CANCEL';
public const REFRESH = 'REFRESH';
public const COUNTER = 'COUNTER';
public const DECLINECOUNTER = 'DECLINECOUNTER';
}

View File

@ -40,4 +40,12 @@ class Imap extends EmailAbstract
return parent::connect($user, $pass);
}
/**
* {@inheritdoc}
*/
public function send() : bool
{
}
}

View File

@ -14,6 +14,9 @@ declare(strict_types=1);
namespace phpOMS\Message\Mail;
use phpOMS\System\CharsetType;
use phpOMS\System\MimeType;
/**
* Mail class.
*
@ -24,13 +27,29 @@ namespace phpOMS\Message\Mail;
*/
class Mail
{
/**
* Mail id.
*
* @var string
* @since 1.0.0
*/
protected string $id = '';
/**
* Mail from.
*
* @var string
* @since 1.0.0
*/
protected $from = '';
protected string $from = '';
/**
* Mail from.
*
* @var string
* @since 1.0.0
*/
protected string $fromName = '';
/**
* Mail to.
@ -38,7 +57,7 @@ class Mail
* @var array
* @since 1.0.0
*/
protected $to = [];
protected array $to = [];
/**
* Mail subject.
@ -46,7 +65,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $subject = '';
protected string $subject = '';
/**
* Mail cc.
@ -54,15 +73,7 @@ class Mail
* @var array
* @since 1.0.0
*/
protected $cc = [];
/**
* Mail reply to.
*
* @var array
* @since 1.0.0
*/
protected $replyTo = [];
protected array $cc = [];
/**
* Mail bcc.
@ -70,7 +81,7 @@ class Mail
* @var array
* @since 1.0.0
*/
protected $bcc = [];
protected array $bcc = [];
/**
* Mail attachments.
@ -78,7 +89,7 @@ class Mail
* @var array
* @since 1.0.0
*/
protected $attachment = [];
protected array $attachment = [];
/**
* Mail body.
@ -86,7 +97,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $body = '';
protected string $body = '';
/**
* Mail overview.
@ -94,7 +105,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $overview = '';
protected string $overview = '';
/**
* Mail alt.
@ -102,7 +113,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $bodyAlt = '';
protected string $bodyAlt = '';
/**
* Mail mime.
@ -110,7 +121,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $bodyMime = '';
protected string $bodyMime = '';
/**
* Mail header.
@ -118,7 +129,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $headerMail = '';
protected string $header = '';
/**
* Word wrap.
@ -126,7 +137,7 @@ class Mail
* @var int
* @since 1.0.0
*/
protected $wordWrap = 78;
protected int $wordWrap = 72;
/**
* Encoding.
@ -134,23 +145,23 @@ class Mail
* @var int
* @since 1.0.0
*/
protected $encoding = 0;
protected int $encoding = EncodingType::E_8BIT;
/**
* Mail host name.
* Mail content type.
*
* @var string
* @since 1.0.0
*/
protected $hostname = '';
protected string $contentType = MimeType::M_TXT;
/**
* Mail id.
* Boundaries
*
* @var string
* @var array
* @since 1.0.0
*/
protected $messageId = '';
protected array $boundary = [];
/**
* Mail message type.
@ -158,7 +169,7 @@ class Mail
* @var string
* @since 1.0.0
*/
protected $messageType = '';
protected string $messageType = '';
/**
* Mail from.
@ -166,7 +177,20 @@ class Mail
* @var null|\DateTime
* @since 1.0.0
*/
protected $messageDate = null;
protected ?\DateTime $messageDate = null;
/**
* Should confirm reading
*
* @var bool
* @since 1.0.0
*/
protected bool $confirmReading = false;
private string $signKeyFile = '';
private string $signCertFile = '';
private string $signExtraFile = '';
private string $signKeyPass = '';
/**
* Constructor.
@ -177,7 +201,7 @@ class Mail
*/
public function __construct($id)
{
$this->messageId = $id;
$this->id = $id;
}
/**
@ -194,6 +218,22 @@ class Mail
$this->body = $body;
}
/**
* Set body alt.
*
* @param string $body Mail body
*
* @return void
*
* @since 1.0.0
*/
public function setBodyAlt(string $body) : void
{
$this->bodyAlt = $body;
$this->contentType = MimeType::M_ALT;
$this->setMessageType();
}
/**
* Set body.
*
@ -221,4 +261,447 @@ class Mail
{
$this->encoding = $encoding;
}
/**
* Set content type.
*
* @param int $contentType Mail content type
*
* @return void
*
* @since 1.0.0
*/
public function setContentType(int $contentType) : void
{
$this->contentType = empty($this->bodyAlt) ? $contentType : MimeType::M_ALT;
}
/**
* Set subject
*
* @param string $subject Subject
*
* @return void
*
* @since 1.0.0
*/
public function setSubject(string $subject) : void
{
$this->subject = $subject;
}
/**
* Set the from address
*
* @param string $mail Mail address
* @param string $name Name
*
* @return bool
*
* @since 1.0.0
*/
public function setFrom(string $mail, string $name = '') : bool
{
$mail = $this->normalizeEmailAddress($mail);
$name = $this->normalizeName($name);
if ($mail === null) {
return false;
}
$this->from = $mail;
$this->fromName = $name;
return true;
}
/**
* Add a to address
*
* @param string $mail Mail address
* @param string $name Name
*
* @return bool
*
* @since 1.0.0
*/
public function addTo(string $mail, string $name = '') : bool
{
$mail = $this->normalizeEmailAddress($mail);
$name = \trim($name);
if ($mail === null) {
return false;
}
$this->to[$mail] = $name;
return true;
}
/**
* Get to addresses
*
* @return array
*
* @since 1.0.0
*/
public function getTo() : array
{
return $this->to;
}
/**
* Add a cc address
*
* @param string $mail Mail address
* @param string $name Name
*
* @return bool
*
* @since 1.0.0
*/
public function addCc(string $mail, string $name = '') : bool
{
$mail = $this->normalizeEmailAddress($mail);
$name = \trim($name);
if ($mail === null) {
return false;
}
$this->cc[$mail] = $name;
return true;
}
/**
* Add a bcc address
*
* @param string $mail Mail address
* @param string $name Name
*
* @return bool
*
* @since 1.0.0
*/
public function addBcc(string $mail, string $name = '') : bool
{
$mail = $this->normalizeEmailAddress($mail);
$name = \trim($name);
if ($mail === null) {
return false;
}
$this->bcc[$mail] = $name;
return true;
}
/**
* Add an attachment
*
* @param string $path Path to the file
* @param string $name Name of the file
* @param string $encoding Encoding
* @param string $type Mime type
* @param string $disposition Disposition
*
* @return bool
*
* @since 1.0.0
*/
public function addAttachment(
string $path,
string $name = '',
string $encoding = EncodingType::E_BASE64,
string $type = '',
string $disposition = DispositionType::ATTACHMENT
) : bool {
if ((bool) \preg_match('#^[a-z]+://#i', $path)) {
return false;
}
$info = [];
\preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^.\\\\/]+?)|))[\\\\/.]*$#m', $path, $info);
$filename = $info[2] ?? '';
$this->attachment[] = [
'path' => $path,
'filename' => $filename,
'name' => $name,
'encoding' => $encoding,
'type' => $type,
'disposition' => $disposition,
'???' => $name,
];
$this->setMessageType();
return true;
}
/**
* The email should be confirmed by the receivers
*
* @param string $confirm Should be confirmed?
*
* @return void
*
* @sicne 1.0.0
*/
public function shouldBeConfirmed(bool $confirm = true) : void
{
$this->confirmReading = $confirm;
}
/**
* Normalize an email address
*
* @param string $mail Mail address
*
* @return null|string
*
* @since 1.0.0
*/
private function normalizeEmailAddress(string $mail) : ?string
{
$mail = \trim($mail);
$pos = \strrpos($mail, '@');
if ($pos === false || !\filter_var($mail, \FILTER_VALIDATE_EMAIL)) {
return null;
}
$normalized = \idn_to_ascii($mail);
return $normalized === false ? $mail : $normalized;
}
/**
* Normalize an email name
*
* @param string $name Name
*
* @return string
*
* @since1 1.0.0
*/
private function normalizeName(string $name) : string
{
return \trim(\preg_replace("/[\r\n]+/", '', $name));
}
/**
* Parsing an email containing a name
*
* @param string $mail Mail string
*
* @return array
*
* @since 1.0.0
*/
private function parseEmailAddress(string $mail) : array
{
$addresses = [];
$list = \explode(',', $mail);
foreach ($list as $address) {
$address = \trim($address);
if (\stripos($address, '<') === false) {
if (($address = $this->normalizeEmailAddress($address)) !== null) {
$addresses[$address] = '';
}
} else {
$parts = \explode('<', $address);
$address = \trim(\str_replace('>', '', $parts[1]));
if (($address = $this->normalizeEmailAddress($address)) !== null) {
$addresses[$address] = \trim(\str_replace(['"', '\''], '', $parts[0]));
}
}
}
return $addresses;
}
/**
* Check if text has none ascii characters
*
* @param string $text Text to check
*
* @return bool
*
* @since 1.0.0
*/
private function hasNoneASCII(string $text) : bool
{
return (bool) \preg_match('/[\x80-\xFF]/', $text);
}
/**
* Define the message type based on the content
*
* @return void
*
* @since 1.0.0
*/
private function setMessageType() : void
{
$this->messageType = '';
$type = [];
if (!empty($this->bodyAlt)) {
$type[] = DispositionType::ALT;
}
foreach ($this->attachment as $attachment) {
if ($attachment['disposition'] === DispositionType::INLINE) {
$type[] = DispositionType::INLINE;
} elseif ($attachment['disposition'] === DispositionType::ATTACHMENT) {
$type[] = DispositionType::ATTACHMENT;
}
}
$this->messageType = \implode('_', $type);
$this->messageType = empty($this->messageType) ? DispositionType::PLAIN : $this->messageType;
}
/**
* Create the mail body
*
* @return string
*
* @since 1.0.0
*/
public function createBody() : string
{
$this->id = empty($this->id) ? $this->generatedId() : $this->id;
$output = '';
$this->boundary[0] = 'b0_' . $this->id;
$this->boundary[1] = 'b1_' . $this->id;
$this->boundary[2] = 'b2_' . $this->id;
$this->boundary[3] = 'b3_' . $this->id;
$output .= !empty($this->signKeyFile) ? $this->generateMimeHeader() . $this->endOfLine : '';
$body = $this->wrapText($this->body, $this->wordWrap, false);
return $output;
}
/**
* Normalize text
*
* Line break
*
* @param string $text Text to normalized
* @param string $lb Line break
*/
private function normalizeText(string $text, string $lb = "\n") : string
{
return \str_replace(["\r\n", "\r", "\n"], $lb, $text);
}
/**
* Generate a random id
*
* @return string
*
* @since 1.0.0
*/
private function generatedId() : string
{
$rand = '';
try {
$rand = \random_bytes(32);
} catch (\Throwable $t) {
$rand = \hash('sha256', \uniqid((string) \mt_rand(), true), true);
}
return \base64_encode(\hash('sha256', $rand, true));
}
/**
* Generate the mime header
*
* @return string
*
* @since 1.0.0
*/
private function generateMimeHeader() : string
{
$mime = '';
$isMultipart = true;
switch ($this->messageType) {
case DispositionType::INLINE:
$mime .= 'Content-Type:' . MimeType::M_RELATED . ';' . $this->endOfLine;;
$mime .= ' boundary="' . $this->boundary[0] . '"' . $this->endOfLine;
break;
case DispositionType::ATTACHMENT:
case DispositionType::INLINE . '_' . DispositionType::ATTACHMENT:
case DispositionType::ALT . '_' . DispositionType::ATTACHMENT:
case DispositionType::ALT . '_' . DispositionType::INLINE . '_' . DispositionType::ATTACHMENT:
$mime .= 'Content-Type:' . MimeType::M_MIXED . ';' . $this->endOfLine;;
$mime .= ' boundary="' . $this->boundary[0] . '"' . $this->endOfLine;
break;
case DispositionType::ALT:
case DispositionType::ALT . '_' . DispositionType::INLINE:
$mime .= 'Content-Type:' . MimeType::M_ALT . ';' . $this->endOfLine;;
$mime .= ' boundary="' . $this->boundary[0] . '"' . $this->endOfLine;
break;
default:
$mime .= 'Content-Type:' . $this->contentType . '; charset=' . CharsetType::UTF_8 . ';' . $this->endOfLine;;
$isMultipart = false;
}
return $isMultipart && $this->encoding !== EncodingType::E_7BIT
? 'Content-Transfer-Encoding:' . $this->encoding . ';' . $this->endOfLine
: $mime;
}
private function wrapText(string $text, int $length, bool $quoted = false) : string
{
if ($length < 1) {
return $text;
}
$softEndOfLine = $quoted ? ' =' . $this->endOfLine : $this->endOfLine;
$text = $this->normalizeText($text, $this->endOfLine);
$text = \rtrim($text, "\r\n");
$lines = \explode($this->endOfLine, $text);
$buffer = '';
$output = '';
foreach ($lines as $line) {
$words = \explode(' ', $line);
foreach ($words as $word) {
if ($quoted && \strlen($word) > $length) {
} else {
$oldBuf = $buffer;
$buffer .= $word . ' ';
if (\strlen($buffer) > $length) {
$output .= \rtrim($oldBuf) . $softEndOfLine;
$buffer = $word;
}
}
}
$output .= \rtrim($buffer) . $this->endOfLine;
}
return $output;
}
}

View File

@ -40,4 +40,12 @@ class Pop3 extends EmailAbstract
return parent::connect();
}
/**
* {@inheritdoc}
*/
public function send() : bool
{
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Message\Mail
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Message\Mail;
use phpOMS\Stdlib\Base\Enum;
/**
* Submit enum.
*
* @package phpOMS\Message\Mail
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
abstract class SubmitType extends Enum
{
public const SMTP = 'smtp';
public const MAIL = 'mail';
public const SENDMAIL = 'sendmail';
public const QMAIL = 'qmail';
}