Файловый менеджер - Редактировать - /home/lakoyani/lakoyani.com.fj/swiftmailer.tar
Назад
swiftmailer/lib/classes/Swift/Encoder/Base64Encoder.php 0000777 00000003073 14710744267 0017033 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Base 64 Encoding in Swift Mailer. * * @author Chris Corbyn */ class Swift_Encoder_Base64Encoder implements Swift_Encoder { /** * Takes an unencoded string and produces a Base64 encoded string from it. * * Base64 encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. * * @param string $string to encode * @param int $firstLineOffset * @param int $maxLineLength optional, 0 indicates the default of 76 bytes * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { if (0 >= $maxLineLength || 76 < $maxLineLength) { $maxLineLength = 76; } $encodedString = base64_encode($string ?? ''); $firstLine = ''; if (0 != $firstLineOffset) { $firstLine = substr( $encodedString, 0, $maxLineLength - $firstLineOffset )."\r\n"; $encodedString = substr( $encodedString, $maxLineLength - $firstLineOffset ); } return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); } /** * Does nothing. */ public function charsetChanged($charset) { } } swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php 0000777 00000004420 14710744267 0017026 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles RFC 2231 specified Encoding in Swift Mailer. * * @author Chris Corbyn */ class Swift_Encoder_Rfc2231Encoder implements Swift_Encoder { /** * A character stream to use when reading a string as characters instead of bytes. * * @var Swift_CharacterStream */ private $charStream; /** * Creates a new Rfc2231Encoder using the given character stream instance. */ public function __construct(Swift_CharacterStream $charStream) { $this->charStream = $charStream; } /** * Takes an unencoded string and produces a string encoded according to * RFC 2231 from it. * * @param string $string * @param int $firstLineOffset * @param int $maxLineLength optional, 0 indicates the default of 75 bytes * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { $lines = []; $lineCount = 0; $lines[] = ''; $currentLine = &$lines[$lineCount++]; if (0 >= $maxLineLength) { $maxLineLength = 75; } $this->charStream->flushContents(); $this->charStream->importString($string); $thisLineLength = $maxLineLength - $firstLineOffset; while (false !== $char = $this->charStream->read(4)) { $encodedChar = rawurlencode($char); if (0 != \strlen($currentLine) && \strlen($currentLine.$encodedChar) > $thisLineLength) { $lines[] = ''; $currentLine = &$lines[$lineCount++]; $thisLineLength = $maxLineLength; } $currentLine .= $encodedChar; } return implode("\r\n", $lines); } /** * Updates the charset used. * * @param string $charset */ public function charsetChanged($charset) { $this->charStream->setCharacterSet($charset); } /** * Make a deep copy of object. */ public function __clone() { $this->charStream = clone $this->charStream; } } swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php 0000777 00000024770 14710744267 0016376 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Quoted Printable (QP) Encoding in Swift Mailer. * * Possibly the most accurate RFC 2045 QP implementation found in PHP. * * @author Chris Corbyn */ class Swift_Encoder_QpEncoder implements Swift_Encoder { /** * The CharacterStream used for reading characters (as opposed to bytes). * * @var Swift_CharacterStream */ protected $charStream; /** * A filter used if input should be canonicalized. * * @var Swift_StreamFilter */ protected $filter; /** * Pre-computed QP for HUGE optimization. * * @var string[] */ protected static $qpMap = [ 0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', 255 => '=FF', ]; protected static $safeMapShare = []; /** * A map of non-encoded ascii characters. * * @var string[] */ protected $safeMap = []; /** * Creates a new QpEncoder for the given CharacterStream. * * @param Swift_CharacterStream $charStream to use for reading characters * @param Swift_StreamFilter $filter if input should be canonicalized */ public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) { $this->charStream = $charStream; if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) { $this->initSafeMap(); self::$safeMapShare[$this->getSafeMapShareId()] = $this->safeMap; } else { $this->safeMap = self::$safeMapShare[$this->getSafeMapShareId()]; } $this->filter = $filter; } public function __sleep() { return ['charStream', 'filter']; } public function __wakeup() { if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) { $this->initSafeMap(); self::$safeMapShare[$this->getSafeMapShareId()] = $this->safeMap; } else { $this->safeMap = self::$safeMapShare[$this->getSafeMapShareId()]; } } protected function getSafeMapShareId() { return static::class; } protected function initSafeMap() { foreach (array_merge( [0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { $this->safeMap[$byte] = \chr($byte); } } /** * Takes an unencoded string and produces a QP encoded string from it. * * QP encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. * * @param string $string to encode * @param int $firstLineOffset optional * @param int $maxLineLength optional 0 indicates the default of 76 chars * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { if ($maxLineLength > 76 || $maxLineLength <= 0) { $maxLineLength = 76; } $thisLineLength = $maxLineLength - $firstLineOffset; $lines = []; $lNo = 0; $lines[$lNo] = ''; $currentLine = &$lines[$lNo++]; $size = $lineLen = 0; $this->charStream->flushContents(); $this->charStream->importString($string); // Fetching more than 4 chars at one is slower, as is fetching fewer bytes // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes while (false !== $bytes = $this->nextSequence()) { // If we're filtering the input if (isset($this->filter)) { // If we can't filter because we need more bytes while ($this->filter->shouldBuffer($bytes)) { // Then collect bytes into the buffer if (false === $moreBytes = $this->nextSequence(1)) { break; } foreach ($moreBytes as $b) { $bytes[] = $b; } } // And filter them $bytes = $this->filter->filter($bytes); } $enc = $this->encodeByteSequence($bytes, $size); $i = strpos($enc, '=0D=0A'); $newLineLength = $lineLen + (false === $i ? $size : $i); if ($currentLine && $newLineLength >= $thisLineLength) { $lines[$lNo] = ''; $currentLine = &$lines[$lNo++]; $thisLineLength = $maxLineLength; $lineLen = 0; } $currentLine .= $enc; if (false === $i) { $lineLen += $size; } else { // 6 is the length of '=0D=0A'. $lineLen = $size - strrpos($enc, '=0D=0A') - 6; } } return $this->standardize(implode("=\r\n", $lines)); } /** * Updates the charset used. * * @param string $charset */ public function charsetChanged($charset) { $this->charStream->setCharacterSet($charset); } /** * Encode the given byte array into a verbatim QP form. * * @param int[] $bytes * @param int $size * * @return string */ protected function encodeByteSequence(array $bytes, &$size) { $ret = ''; $size = 0; foreach ($bytes as $b) { if (isset($this->safeMap[$b])) { $ret .= $this->safeMap[$b]; ++$size; } else { $ret .= self::$qpMap[$b]; $size += 3; } } return $ret; } /** * Get the next sequence of bytes to read from the char stream. * * @param int $size number of bytes to read * * @return int[] */ protected function nextSequence($size = 4) { return $this->charStream->readBytes($size); } /** * Make sure CRLF is correct and HT/SPACE are in valid places. * * @param string $string * * @return string */ protected function standardize($string) { $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string ); switch ($end = \ord(substr($string, -1))) { case 0x09: case 0x20: $string = substr_replace($string, self::$qpMap[$end], -1); } return $string; } /** * Make a deep copy of object. */ public function __clone() { $this->charStream = clone $this->charStream; } } swiftmailer/lib/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php 0000777 00000012247 14710744267 0023147 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Processes bytes as they pass through a buffer and replaces sequences in it. * * This stream filter deals with Byte arrays rather than simple strings. * * @author Chris Corbyn */ class Swift_StreamFilters_ByteArrayReplacementFilter implements Swift_StreamFilter { /** The replacement(s) to make */ private $replace; /** The Index for searching */ private $index; /** The Search Tree */ private $tree = []; /** Gives the size of the largest search */ private $treeMaxLen = 0; private $repSize; /** * Create a new ByteArrayReplacementFilter with $search and $replace. * * @param array $search * @param array $replace */ public function __construct($search, $replace) { $this->index = []; $this->tree = []; $this->replace = []; $this->repSize = []; $tree = null; $i = null; $last_size = $size = 0; foreach ($search as $i => $search_element) { if (null !== $tree) { $tree[-1] = min(\count($replace) - 1, $i - 1); $tree[-2] = $last_size; } $tree = &$this->tree; if (\is_array($search_element)) { foreach ($search_element as $k => $char) { $this->index[$char] = true; if (!isset($tree[$char])) { $tree[$char] = []; } $tree = &$tree[$char]; } $last_size = $k + 1; $size = max($size, $last_size); } else { $last_size = 1; if (!isset($tree[$search_element])) { $tree[$search_element] = []; } $tree = &$tree[$search_element]; $size = max($last_size, $size); $this->index[$search_element] = true; } } if (null !== $i) { $tree[-1] = min(\count($replace) - 1, $i); $tree[-2] = $last_size; $this->treeMaxLen = $size; } foreach ($replace as $rep) { if (!\is_array($rep)) { $rep = [$rep]; } $this->replace[] = $rep; } for ($i = \count($this->replace) - 1; $i >= 0; --$i) { $this->replace[$i] = $rep = $this->filter($this->replace[$i], $i); $this->repSize[$i] = \count($rep); } } /** * Returns true if based on the buffer passed more bytes should be buffered. * * @param array $buffer * * @return bool */ public function shouldBuffer($buffer) { $endOfBuffer = end($buffer); return isset($this->index[$endOfBuffer]); } /** * Perform the actual replacements on $buffer and return the result. * * @param array $buffer * @param int $minReplaces * * @return array */ public function filter($buffer, $minReplaces = -1) { if (0 == $this->treeMaxLen) { return $buffer; } $newBuffer = []; $buf_size = \count($buffer); $last_size = 0; for ($i = 0; $i < $buf_size; ++$i) { $search_pos = $this->tree; $last_found = PHP_INT_MAX; // We try to find if the next byte is part of a search pattern for ($j = 0; $j <= $this->treeMaxLen; ++$j) { // We have a new byte for a search pattern if (isset($buffer[$p = $i + $j]) && isset($search_pos[$buffer[$p]])) { $search_pos = $search_pos[$buffer[$p]]; // We have a complete pattern, save, in case we don't find a better match later if (isset($search_pos[-1]) && $search_pos[-1] < $last_found && $search_pos[-1] > $minReplaces) { $last_found = $search_pos[-1]; $last_size = $search_pos[-2]; } } // We got a complete pattern elseif (PHP_INT_MAX !== $last_found) { // Adding replacement datas to output buffer $rep_size = $this->repSize[$last_found]; for ($j = 0; $j < $rep_size; ++$j) { $newBuffer[] = $this->replace[$last_found][$j]; } // We Move cursor forward $i += $last_size - 1; // Edge Case, last position in buffer if ($i >= $buf_size) { $newBuffer[] = $buffer[$i]; } // We start the next loop continue 2; } else { // this byte is not in a pattern and we haven't found another pattern break; } } // Normal byte, move it to output buffer $newBuffer[] = $buffer[$i]; } return $newBuffer; } } swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php 0000777 00000002276 14710744267 0024044 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Creates filters for replacing needles in a string buffer. * * @author Chris Corbyn */ class Swift_StreamFilters_StringReplacementFilterFactory implements Swift_ReplacementFilterFactory { /** Lazy-loaded filters */ private $filters = []; /** * Create a new StreamFilter to replace $search with $replace in a string. * * @param string $search * @param string $replace * * @return Swift_StreamFilter */ public function createFilter($search, $replace) { if (!isset($this->filters[$search][$replace])) { if (!isset($this->filters[$search])) { $this->filters[$search] = []; } if (!isset($this->filters[$search][$replace])) { $this->filters[$search][$replace] = []; } $this->filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace); } return $this->filters[$search][$replace]; } } swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php 0000777 00000003115 14710744267 0022505 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Processes bytes as they pass through a buffer and replaces sequences in it. * * @author Chris Corbyn */ class Swift_StreamFilters_StringReplacementFilter implements Swift_StreamFilter { /** The needle(s) to search for */ private $search; /** The replacement(s) to make */ private $replace; /** * Create a new StringReplacementFilter with $search and $replace. * * @param string|array $search * @param string|array $replace */ public function __construct($search, $replace) { $this->search = $search; $this->replace = $replace; } /** * Returns true if based on the buffer passed more bytes should be buffered. * * @param string $buffer * * @return bool */ public function shouldBuffer($buffer) { if ('' === $buffer) { return false; } $endOfBuffer = substr($buffer, -1); foreach ((array) $this->search as $needle) { if (false !== strpos($needle, $endOfBuffer)) { return true; } } return false; } /** * Perform the actual replacements on $buffer and return the result. * * @param string $buffer * * @return string */ public function filter($buffer) { return str_replace($this->search, $this->replace, $buffer); } } swiftmailer/lib/classes/Swift/KeyCache.php 0000777 00000005362 14710744267 0014607 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Provides a mechanism for storing data using two keys. * * @author Chris Corbyn */ interface Swift_KeyCache { /** Mode for replacing existing cached data */ const MODE_WRITE = 1; /** Mode for appending data to the end of existing cached data */ const MODE_APPEND = 2; /** * Set a string into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param string $string * @param int $mode */ public function setString($nsKey, $itemKey, $string, $mode); /** * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param int $mode */ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode); /** * Provides a ByteStream which when written to, writes data to $itemKey. * * NOTE: The stream will always write in append mode. * If the optional third parameter is passed all writes will go through $is. * * @param string $nsKey * @param string $itemKey * @param Swift_InputByteStream $is optional input stream * * @return Swift_InputByteStream */ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $is = null); /** * Get data back out of the cache as a string. * * @param string $nsKey * @param string $itemKey * * @return string */ public function getString($nsKey, $itemKey); /** * Get data back out of the cache as a ByteStream. * * @param string $nsKey * @param string $itemKey * @param Swift_InputByteStream $is stream to write the data to */ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is); /** * Check if the given $itemKey exists in the namespace $nsKey. * * @param string $nsKey * @param string $itemKey * * @return bool */ public function hasKey($nsKey, $itemKey); /** * Clear data for $itemKey in the namespace $nsKey if it exists. * * @param string $nsKey * @param string $itemKey */ public function clearKey($nsKey, $itemKey); /** * Clear all data in the namespace $nsKey if it exists. * * @param string $nsKey */ public function clearAll($nsKey); } swiftmailer/lib/classes/Swift/IdGenerator.php 0000777 00000000661 14710744267 0015333 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Message ID generator. */ interface Swift_IdGenerator { /** * Returns a globally unique string to use for Message-ID or Content-ID. * * @return string */ public function generateId(); } swiftmailer/lib/classes/Swift/CharacterReader.php 0000777 00000003314 14710744267 0016145 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Analyzes characters for a specific character set. * * @author Chris Corbyn * @author Xavier De Cock <xdecock@gmail.com> */ interface Swift_CharacterReader { const MAP_TYPE_INVALID = 0x01; const MAP_TYPE_FIXED_LEN = 0x02; const MAP_TYPE_POSITIONS = 0x03; /** * Returns the complete character map. * * @param string $string * @param int $startOffset * @param array $currentMap * @param mixed $ignoredChars * * @return int */ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars); /** * Returns the mapType, see constants. * * @return int */ public function getMapType(); /** * Returns an integer which specifies how many more bytes to read. * * A positive integer indicates the number of more bytes to fetch before invoking * this method again. * * A value of zero means this is already a valid character. * A value of -1 means this cannot possibly be a valid character. * * @param int[] $bytes * @param int $size * * @return int */ public function validateByteSequence($bytes, $size); /** * Returns the number of bytes which should be read to start each character. * * For fixed width character sets this should be the number of octets-per-character. * For multibyte character sets this will probably be 1. * * @return int */ public function getInitialByteSize(); } swiftmailer/lib/classes/Swift/DependencyContainer.php 0000777 00000023310 14710744267 0017045 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Dependency Injection container. * * @author Chris Corbyn */ class Swift_DependencyContainer { /** Constant for literal value types */ const TYPE_VALUE = 0x00001; /** Constant for new instance types */ const TYPE_INSTANCE = 0x00010; /** Constant for shared instance types */ const TYPE_SHARED = 0x00100; /** Constant for aliases */ const TYPE_ALIAS = 0x01000; /** Constant for arrays */ const TYPE_ARRAY = 0x10000; /** Singleton instance */ private static $instance = null; /** The data container */ private $store = []; /** The current endpoint in the data container */ private $endPoint; /** * Constructor should not be used. * * Use {@link getInstance()} instead. */ public function __construct() { } /** * Returns a singleton of the DependencyContainer. * * @return self */ public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * List the names of all items stored in the Container. * * @return array */ public function listItems() { return array_keys($this->store); } /** * Test if an item is registered in this container with the given name. * * @see register() * * @param string $itemName * * @return bool */ public function has($itemName) { return \array_key_exists($itemName, $this->store) && isset($this->store[$itemName]['lookupType']); } /** * Lookup the item with the given $itemName. * * @see register() * * @param string $itemName * * @return mixed * * @throws Swift_DependencyException If the dependency is not found */ public function lookup($itemName) { if (!$this->has($itemName)) { throw new Swift_DependencyException('Cannot lookup dependency "'.$itemName.'" since it is not registered.'); } switch ($this->store[$itemName]['lookupType']) { case self::TYPE_ALIAS: return $this->createAlias($itemName); case self::TYPE_VALUE: return $this->getValue($itemName); case self::TYPE_INSTANCE: return $this->createNewInstance($itemName); case self::TYPE_SHARED: return $this->createSharedInstance($itemName); case self::TYPE_ARRAY: return $this->createDependenciesFor($itemName); } } /** * Create an array of arguments passed to the constructor of $itemName. * * @param string $itemName * * @return array */ public function createDependenciesFor($itemName) { $args = []; if (isset($this->store[$itemName]['args'])) { $args = $this->resolveArgs($this->store[$itemName]['args']); } return $args; } /** * Register a new dependency with $itemName. * * This method returns the current DependencyContainer instance because it * requires the use of the fluid interface to set the specific details for the * dependency. * * @see asNewInstanceOf(), asSharedInstanceOf(), asValue() * * @param string $itemName * * @return $this */ public function register($itemName) { $this->store[$itemName] = []; $this->endPoint = &$this->store[$itemName]; return $this; } /** * Specify the previously registered item as a literal value. * * {@link register()} must be called before this will work. * * @param mixed $value * * @return $this */ public function asValue($value) { $endPoint = &$this->getEndPoint(); $endPoint['lookupType'] = self::TYPE_VALUE; $endPoint['value'] = $value; return $this; } /** * Specify the previously registered item as an alias of another item. * * @param string $lookup * * @return $this */ public function asAliasOf($lookup) { $endPoint = &$this->getEndPoint(); $endPoint['lookupType'] = self::TYPE_ALIAS; $endPoint['ref'] = $lookup; return $this; } /** * Specify the previously registered item as a new instance of $className. * * {@link register()} must be called before this will work. * Any arguments can be set with {@link withDependencies()}, * {@link addConstructorValue()} or {@link addConstructorLookup()}. * * @see withDependencies(), addConstructorValue(), addConstructorLookup() * * @param string $className * * @return $this */ public function asNewInstanceOf($className) { $endPoint = &$this->getEndPoint(); $endPoint['lookupType'] = self::TYPE_INSTANCE; $endPoint['className'] = $className; return $this; } /** * Specify the previously registered item as a shared instance of $className. * * {@link register()} must be called before this will work. * * @param string $className * * @return $this */ public function asSharedInstanceOf($className) { $endPoint = &$this->getEndPoint(); $endPoint['lookupType'] = self::TYPE_SHARED; $endPoint['className'] = $className; return $this; } /** * Specify the previously registered item as array of dependencies. * * {@link register()} must be called before this will work. * * @return $this */ public function asArray() { $endPoint = &$this->getEndPoint(); $endPoint['lookupType'] = self::TYPE_ARRAY; return $this; } /** * Specify a list of injected dependencies for the previously registered item. * * This method takes an array of lookup names. * * @see addConstructorValue(), addConstructorLookup() * * @return $this */ public function withDependencies(array $lookups) { $endPoint = &$this->getEndPoint(); $endPoint['args'] = []; foreach ($lookups as $lookup) { $this->addConstructorLookup($lookup); } return $this; } /** * Specify a literal (non looked up) value for the constructor of the * previously registered item. * * @see withDependencies(), addConstructorLookup() * * @param mixed $value * * @return $this */ public function addConstructorValue($value) { $endPoint = &$this->getEndPoint(); if (!isset($endPoint['args'])) { $endPoint['args'] = []; } $endPoint['args'][] = ['type' => 'value', 'item' => $value]; return $this; } /** * Specify a dependency lookup for the constructor of the previously * registered item. * * @see withDependencies(), addConstructorValue() * * @param string $lookup * * @return $this */ public function addConstructorLookup($lookup) { $endPoint = &$this->getEndPoint(); if (!isset($this->endPoint['args'])) { $endPoint['args'] = []; } $endPoint['args'][] = ['type' => 'lookup', 'item' => $lookup]; return $this; } /** Get the literal value with $itemName */ private function getValue($itemName) { return $this->store[$itemName]['value']; } /** Resolve an alias to another item */ private function createAlias($itemName) { return $this->lookup($this->store[$itemName]['ref']); } /** Create a fresh instance of $itemName */ private function createNewInstance($itemName) { $reflector = new ReflectionClass($this->store[$itemName]['className']); if ($reflector->getConstructor()) { return $reflector->newInstanceArgs( $this->createDependenciesFor($itemName) ); } return $reflector->newInstance(); } /** Create and register a shared instance of $itemName */ private function createSharedInstance($itemName) { if (!isset($this->store[$itemName]['instance'])) { $this->store[$itemName]['instance'] = $this->createNewInstance($itemName); } return $this->store[$itemName]['instance']; } /** Get the current endpoint in the store */ private function &getEndPoint() { if (!isset($this->endPoint)) { throw new BadMethodCallException('Component must first be registered by calling register()'); } return $this->endPoint; } /** Get an argument list with dependencies resolved */ private function resolveArgs(array $args) { $resolved = []; foreach ($args as $argDefinition) { switch ($argDefinition['type']) { case 'lookup': $resolved[] = $this->lookupRecursive($argDefinition['item']); break; case 'value': $resolved[] = $argDefinition['item']; break; } } return $resolved; } /** Resolve a single dependency with an collections */ private function lookupRecursive($item) { if (\is_array($item)) { $collection = []; foreach ($item as $k => $v) { $collection[$k] = $this->lookupRecursive($v); } return $collection; } return $this->lookup($item); } } swiftmailer/lib/classes/Swift/Events/EventListener.php 0000777 00000000537 14710744267 0017165 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An identity interface which all EventListeners must extend. * * @author Chris Corbyn */ interface Swift_Events_EventListener { } swiftmailer/lib/classes/Swift/Events/SendListener.php 0000777 00000001233 14710744267 0016767 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Listens for Messages being sent from within the Transport system. * * @author Chris Corbyn */ interface Swift_Events_SendListener extends Swift_Events_EventListener { /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt); /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt); } swiftmailer/lib/classes/Swift/Events/ResponseEvent.php 0000777 00000002365 14710744267 0017177 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Generated when a response is received on a SMTP connection. * * @author Chris Corbyn */ class Swift_Events_ResponseEvent extends Swift_Events_EventObject { /** * The overall result. * * @var bool */ private $valid; /** * The response received from the server. * * @var string */ private $response; /** * Create a new ResponseEvent for $source and $response. * * @param string $response * @param bool $valid */ public function __construct(Swift_Transport $source, $response, $valid = false) { parent::__construct($source); $this->response = $response; $this->valid = $valid; } /** * Get the response which was received from the server. * * @return string */ public function getResponse() { return $this->response; } /** * Get the success status of this Event. * * @return bool */ public function isValid() { return $this->valid; } } swiftmailer/lib/classes/Swift/Events/Event.php 0000777 00000001411 14710744267 0015447 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * The minimum interface for an Event. * * @author Chris Corbyn */ interface Swift_Events_Event { /** * Get the source object of this event. * * @return object */ public function getSource(); /** * Prevent this Event from bubbling any further up the stack. * * @param bool $cancel, optional */ public function cancelBubble($cancel = true); /** * Returns true if this Event will not bubble any further up the stack. * * @return bool */ public function bubbleCancelled(); } swiftmailer/lib/classes/Swift/Events/SimpleEventDispatcher.php 0000777 00000010402 14710744267 0020630 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * The EventDispatcher which handles the event dispatching layer. * * @author Chris Corbyn */ class Swift_Events_SimpleEventDispatcher implements Swift_Events_EventDispatcher { /** A map of event types to their associated listener types */ private $eventMap = []; /** Event listeners bound to this dispatcher */ private $listeners = []; /** * Create a new EventDispatcher. */ public function __construct() { $this->eventMap = [ 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener', 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener', 'Swift_Events_SendEvent' => 'Swift_Events_SendListener', 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener', 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener', ]; } /** * Create a new SendEvent for $source and $message. * * @return Swift_Events_SendEvent */ public function createSendEvent(Swift_Transport $source, Swift_Mime_SimpleMessage $message) { return new Swift_Events_SendEvent($source, $message); } /** * Create a new CommandEvent for $source and $command. * * @param string $command That will be executed * @param array $successCodes That are needed * * @return Swift_Events_CommandEvent */ public function createCommandEvent(Swift_Transport $source, $command, $successCodes = []) { return new Swift_Events_CommandEvent($source, $command, $successCodes); } /** * Create a new ResponseEvent for $source and $response. * * @param string $response * @param bool $valid If the response is valid * * @return Swift_Events_ResponseEvent */ public function createResponseEvent(Swift_Transport $source, $response, $valid) { return new Swift_Events_ResponseEvent($source, $response, $valid); } /** * Create a new TransportChangeEvent for $source. * * @return Swift_Events_TransportChangeEvent */ public function createTransportChangeEvent(Swift_Transport $source) { return new Swift_Events_TransportChangeEvent($source); } /** * Create a new TransportExceptionEvent for $source. * * @return Swift_Events_TransportExceptionEvent */ public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex) { return new Swift_Events_TransportExceptionEvent($source, $ex); } /** * Bind an event listener to this dispatcher. */ public function bindEventListener(Swift_Events_EventListener $listener) { foreach ($this->listeners as $l) { // Already loaded if ($l === $listener) { return; } } $this->listeners[] = $listener; } /** * Dispatch the given Event to all suitable listeners. * * @param string $target method */ public function dispatchEvent(Swift_Events_EventObject $evt, $target) { $bubbleQueue = $this->prepareBubbleQueue($evt); $this->bubble($bubbleQueue, $evt, $target); } /** Queue listeners on a stack ready for $evt to be bubbled up it */ private function prepareBubbleQueue(Swift_Events_EventObject $evt) { $bubbleQueue = []; $evtClass = \get_class($evt); foreach ($this->listeners as $listener) { if (\array_key_exists($evtClass, $this->eventMap) && ($listener instanceof $this->eventMap[$evtClass])) { $bubbleQueue[] = $listener; } } return $bubbleQueue; } /** Bubble $evt up the stack calling $target() on each listener */ private function bubble(array &$bubbleQueue, Swift_Events_EventObject $evt, $target) { if (!$evt->bubbleCancelled() && $listener = array_shift($bubbleQueue)) { $listener->$target($evt); $this->bubble($bubbleQueue, $evt, $target); } } } swiftmailer/lib/classes/Swift/Events/SendEvent.php 0000777 00000005135 14710744267 0016270 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Generated when a message is being sent. * * @author Chris Corbyn */ class Swift_Events_SendEvent extends Swift_Events_EventObject { /** Sending has yet to occur */ const RESULT_PENDING = 0x0001; /** Email is spooled, ready to be sent */ const RESULT_SPOOLED = 0x0011; /** Sending was successful */ const RESULT_SUCCESS = 0x0010; /** Sending worked, but there were some failures */ const RESULT_TENTATIVE = 0x0100; /** Sending failed */ const RESULT_FAILED = 0x1000; /** * The Message being sent. * * @var Swift_Mime_SimpleMessage */ private $message; /** * Any recipients which failed after sending. * * @var string[] */ private $failedRecipients = []; /** * The overall result as a bitmask from the class constants. * * @var int */ private $result; /** * Create a new SendEvent for $source and $message. */ public function __construct(Swift_Transport $source, Swift_Mime_SimpleMessage $message) { parent::__construct($source); $this->message = $message; $this->result = self::RESULT_PENDING; } /** * Get the Transport used to send the Message. * * @return Swift_Transport */ public function getTransport() { return $this->getSource(); } /** * Get the Message being sent. * * @return Swift_Mime_SimpleMessage */ public function getMessage() { return $this->message; } /** * Set the array of addresses that failed in sending. * * @param array $recipients */ public function setFailedRecipients($recipients) { $this->failedRecipients = $recipients; } /** * Get an recipient addresses which were not accepted for delivery. * * @return string[] */ public function getFailedRecipients() { return $this->failedRecipients; } /** * Set the result of sending. * * @param int $result */ public function setResult($result) { $this->result = $result; } /** * Get the result of this Event. * * The return value is a bitmask from * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED} * * @return int */ public function getResult() { return $this->result; } } swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php 0000777 00000001064 14710744267 0020476 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Generated when the state of a Transport is changed (i.e. stopped/started). * * @author Chris Corbyn */ class Swift_Events_TransportChangeEvent extends Swift_Events_EventObject { /** * Get the Transport. * * @return Swift_Transport */ public function getTransport() { return $this->getSource(); } } swiftmailer/lib/classes/Swift/Events/EventDispatcher.php 0000777 00000003721 14710744267 0017464 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Interface for the EventDispatcher which handles the event dispatching layer. * * @author Chris Corbyn */ interface Swift_Events_EventDispatcher { /** * Create a new SendEvent for $source and $message. * * @return Swift_Events_SendEvent */ public function createSendEvent(Swift_Transport $source, Swift_Mime_SimpleMessage $message); /** * Create a new CommandEvent for $source and $command. * * @param string $command That will be executed * @param array $successCodes That are needed * * @return Swift_Events_CommandEvent */ public function createCommandEvent(Swift_Transport $source, $command, $successCodes = []); /** * Create a new ResponseEvent for $source and $response. * * @param string $response * @param bool $valid If the response is valid * * @return Swift_Events_ResponseEvent */ public function createResponseEvent(Swift_Transport $source, $response, $valid); /** * Create a new TransportChangeEvent for $source. * * @return Swift_Events_TransportChangeEvent */ public function createTransportChangeEvent(Swift_Transport $source); /** * Create a new TransportExceptionEvent for $source. * * @return Swift_Events_TransportExceptionEvent */ public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex); /** * Bind an event listener to this dispatcher. */ public function bindEventListener(Swift_Events_EventListener $listener); /** * Dispatch the given Event to all suitable listeners. * * @param string $target method */ public function dispatchEvent(Swift_Events_EventObject $evt, $target); } swiftmailer/lib/classes/Swift/Events/CommandEvent.php 0000777 00000002534 14710744267 0016755 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Generated when a command is sent over an SMTP connection. * * @author Chris Corbyn */ class Swift_Events_CommandEvent extends Swift_Events_EventObject { /** * The command sent to the server. * * @var string */ private $command; /** * An array of codes which a successful response will contain. * * @var int[] */ private $successCodes = []; /** * Create a new CommandEvent for $source with $command. * * @param string $command * @param array $successCodes */ public function __construct(Swift_Transport $source, $command, $successCodes = []) { parent::__construct($source); $this->command = $command; $this->successCodes = $successCodes; } /** * Get the command which was sent to the server. * * @return string */ public function getCommand() { return $this->command; } /** * Get the numeric response codes which indicate success for this command. * * @return int[] */ public function getSuccessCodes() { return $this->successCodes; } } swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php 0000777 00000001744 14710744267 0021207 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Listens for changes within the Transport system. * * @author Chris Corbyn */ interface Swift_Events_TransportChangeListener extends Swift_Events_EventListener { /** * Invoked just before a Transport is started. */ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt); /** * Invoked immediately after the Transport is started. */ public function transportStarted(Swift_Events_TransportChangeEvent $evt); /** * Invoked just before a Transport is stopped. */ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt); /** * Invoked immediately after the Transport is stopped. */ public function transportStopped(Swift_Events_TransportChangeEvent $evt); } swiftmailer/lib/classes/Swift/Events/CommandListener.php 0000777 00000001013 14710744267 0017450 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Listens for Transports to send commands to the server. * * @author Chris Corbyn */ interface Swift_Events_CommandListener extends Swift_Events_EventListener { /** * Invoked immediately following a command being sent. */ public function commandSent(Swift_Events_CommandEvent $evt); } swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php 0000777 00000001075 14710744267 0021755 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Listens for Exceptions thrown from within the Transport system. * * @author Chris Corbyn */ interface Swift_Events_TransportExceptionListener extends Swift_Events_EventListener { /** * Invoked as a TransportException is thrown in the Transport system. */ public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt); } swiftmailer/lib/classes/Swift/Events/EventObject.php 0000777 00000002404 14710744267 0016601 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A base Event which all Event classes inherit from. * * @author Chris Corbyn */ class Swift_Events_EventObject implements Swift_Events_Event { /** The source of this Event */ private $source; /** The state of this Event (should it bubble up the stack?) */ private $bubbleCancelled = false; /** * Create a new EventObject originating at $source. * * @param object $source */ public function __construct($source) { $this->source = $source; } /** * Get the source object of this event. * * @return object */ public function getSource() { return $this->source; } /** * Prevent this Event from bubbling any further up the stack. */ public function cancelBubble($cancel = true) { $this->bubbleCancelled = $cancel; } /** * Returns true if this Event will not bubble any further up the stack. * * @return bool */ public function bubbleCancelled() { return $this->bubbleCancelled; } } swiftmailer/lib/classes/Swift/Events/ResponseListener.php 0000777 00000001016 14710744267 0017673 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Listens for responses from a remote SMTP server. * * @author Chris Corbyn */ interface Swift_Events_ResponseListener extends Swift_Events_EventListener { /** * Invoked immediately following a response coming back. */ public function responseReceived(Swift_Events_ResponseEvent $evt); } swiftmailer/lib/classes/Swift/Events/TransportExceptionEvent.php 0000777 00000001672 14710744267 0021254 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Generated when a TransportException is thrown from the Transport system. * * @author Chris Corbyn */ class Swift_Events_TransportExceptionEvent extends Swift_Events_EventObject { /** * The Exception thrown. * * @var Swift_TransportException */ private $exception; /** * Create a new TransportExceptionEvent for $transport. */ public function __construct(Swift_Transport $transport, Swift_TransportException $ex) { parent::__construct($transport); $this->exception = $ex; } /** * Get the TransportException thrown. * * @return Swift_TransportException */ public function getException() { return $this->exception; } } swiftmailer/lib/classes/Swift/DependencyException.php 0000777 00000001114 14710744267 0017057 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * DependencyException gets thrown when a requested dependency is missing. * * @author Chris Corbyn */ class Swift_DependencyException extends Swift_SwiftException { /** * Create a new DependencyException with $message. * * @param string $message */ public function __construct($message) { parent::__construct($message); } } swiftmailer/lib/classes/Swift/NullTransport.php 0000777 00000001241 14710744267 0015752 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Pretends messages have been sent, but just ignores them. * * @author Fabien Potencier */ class Swift_NullTransport extends Swift_Transport_NullTransport { public function __construct() { \call_user_func_array( [$this, 'Swift_Transport_NullTransport::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('transport.null') ); } } swiftmailer/lib/classes/Swift/Mailer.php 0000777 00000005006 14710744267 0014337 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Swift Mailer class. * * @author Chris Corbyn */ class Swift_Mailer { /** The Transport used to send messages */ private $transport; /** * Create a new Mailer using $transport for delivery. */ public function __construct(Swift_Transport $transport) { $this->transport = $transport; } /** * Create a new class instance of one of the message services. * * For example 'mimepart' would create a 'message.mimepart' instance * * @param string $service * * @return object */ public function createMessage($service = 'message') { return Swift_DependencyContainer::getInstance() ->lookup('message.'.$service); } /** * Send the given Message like it would be sent in a mail client. * * All recipients (with the exception of Bcc) will be able to see the other * recipients this message was sent to. * * Recipient/sender data will be retrieved from the Message object. * * The return value is the number of recipients who were accepted for * delivery. * * @param array $failedRecipients An array of failures by-reference * * @return int The number of successful recipients. Can be 0 which indicates failure */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { $failedRecipients = (array) $failedRecipients; // FIXME: to be removed in 7.0 (as transport must now start itself on send) if (!$this->transport->isStarted()) { $this->transport->start(); } $sent = 0; try { $sent = $this->transport->send($message, $failedRecipients); } catch (Swift_RfcComplianceException $e) { foreach ($message->getTo() as $address => $name) { $failedRecipients[] = $address; } } return $sent; } /** * Register a plugin using a known unique key (e.g. myPlugin). */ public function registerPlugin(Swift_Events_EventListener $plugin) { $this->transport->registerPlugin($plugin); } /** * The Transport used to send messages. * * @return Swift_Transport */ public function getTransport() { return $this->transport; } } swiftmailer/lib/classes/Swift/Signers/BodySigner.php 0000777 00000001302 14710744267 0016600 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Body Signer Interface used to apply Body-Based Signature to a message. * * @author Xavier De Cock <xdecock@gmail.com> */ interface Swift_Signers_BodySigner extends Swift_Signer { /** * Change the Swift_Signed_Message to apply the singing. * * @return self */ public function signMessage(Swift_Message $message); /** * Return the list of header a signer might tamper. * * @return array */ public function getAlteredHeaders(); } swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php 0000777 00000002454 14710744267 0017104 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Header Signer Interface used to apply Header-Based Signature to a message. * * @author Xavier De Cock <xdecock@gmail.com> */ interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream { /** * Exclude an header from the signed headers. * * @param string $header_name * * @return self */ public function ignoreHeader($header_name); /** * Prepare the Signer to get a new Body. * * @return self */ public function startBody(); /** * Give the signal that the body has finished streaming. * * @return self */ public function endBody(); /** * Give the headers already given. * * @return self */ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers); /** * Add the header(s) to the headerSet. * * @return self */ public function addSignature(Swift_Mime_SimpleHeaderSet $headers); /** * Return the list of header a signer might tamper. * * @return array */ public function getAlteredHeaders(); } swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php 0000777 00000042143 14710744267 0016437 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * DKIM Signer used to apply DKIM Signature to a message. * * @author Xavier De Cock <xdecock@gmail.com> */ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner { /** * PrivateKey. * * @var string */ protected $privateKey; /** * DomainName. * * @var string */ protected $domainName; /** * Selector. * * @var string */ protected $selector; private $passphrase = ''; /** * Hash algorithm used. * * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256. * * @var string */ protected $hashAlgorithm = 'rsa-sha256'; /** * Body canon method. * * @var string */ protected $bodyCanon = 'simple'; /** * Header canon method. * * @var string */ protected $headerCanon = 'simple'; /** * Headers not being signed. * * @var array */ protected $ignoredHeaders = ['return-path' => true]; /** * Signer identity. * * @var string */ protected $signerIdentity; /** * BodyLength. * * @var int */ protected $bodyLen = 0; /** * Maximum signedLen. * * @var int */ protected $maxLen = PHP_INT_MAX; /** * Embbed bodyLen in signature. * * @var bool */ protected $showLen = false; /** * When the signature has been applied (true means time()), false means not embedded. * * @var mixed */ protected $signatureTimestamp = true; /** * When will the signature expires false means not embedded, if sigTimestamp is auto * Expiration is relative, otherwise it's absolute. * * @var int */ protected $signatureExpiration = false; /** * Must we embed signed headers? * * @var bool */ protected $debugHeaders = false; // work variables /** * Headers used to generate hash. * * @var array */ protected $signedHeaders = []; /** * If debugHeaders is set store debugData here. * * @var string[] */ private $debugHeadersData = []; /** * Stores the bodyHash. * * @var string */ private $bodyHash = ''; /** * Stores the signature header. * * @var Swift_Mime_Headers_ParameterizedHeader */ protected $dkimHeader; private $bodyHashHandler; private $headerHash; private $headerCanonData = ''; private $bodyCanonEmptyCounter = 0; private $bodyCanonIgnoreStart = 2; private $bodyCanonSpace = false; private $bodyCanonLastChar = null; private $bodyCanonLine = ''; private $bound = []; /** * Constructor. * * @param string $privateKey * @param string $domainName * @param string $selector * @param string $passphrase */ public function __construct($privateKey, $domainName, $selector, $passphrase = '') { $this->privateKey = $privateKey; $this->domainName = $domainName; $this->signerIdentity = '@'.$domainName; $this->selector = $selector; $this->passphrase = $passphrase; } /** * Reset the Signer. * * @see Swift_Signer::reset() */ public function reset() { $this->headerHash = null; $this->signedHeaders = []; $this->bodyHash = null; $this->bodyHashHandler = null; $this->bodyCanonIgnoreStart = 2; $this->bodyCanonEmptyCounter = 0; $this->bodyCanonLastChar = null; $this->bodyCanonSpace = false; } /** * Writes $bytes to the end of the stream. * * Writing may not happen immediately if the stream chooses to buffer. If * you want to write these bytes with immediate effect, call {@link commit()} * after calling write(). * * This method returns the sequence ID of the write (i.e. 1 for first, 2 for * second, etc etc). * * @param string $bytes * * @return int * * @throws Swift_IoException */ // TODO fix return public function write($bytes) { $this->canonicalizeBody($bytes); foreach ($this->bound as $is) { $is->write($bytes); } } /** * For any bytes that are currently buffered inside the stream, force them * off the buffer. */ public function commit() { // Nothing to do return; } /** * Attach $is to this stream. * * The stream acts as an observer, receiving all data that is written. * All {@link write()} and {@link flushBuffers()} operations will be mirrored. */ public function bind(Swift_InputByteStream $is) { // Don't have to mirror anything $this->bound[] = $is; return; } /** * Remove an already bound stream. * * If $is is not bound, no errors will be raised. * If the stream currently has any buffered data it will be written to $is * before unbinding occurs. */ public function unbind(Swift_InputByteStream $is) { // Don't have to mirror anything foreach ($this->bound as $k => $stream) { if ($stream === $is) { unset($this->bound[$k]); return; } } } /** * Flush the contents of the stream (empty it) and set the internal pointer * to the beginning. * * @throws Swift_IoException */ public function flushBuffers() { $this->reset(); } /** * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1. * * @param string $hash 'rsa-sha1' or 'rsa-sha256' * * @throws Swift_SwiftException * * @return $this */ public function setHashAlgorithm($hash) { switch ($hash) { case 'rsa-sha1': $this->hashAlgorithm = 'rsa-sha1'; break; case 'rsa-sha256': $this->hashAlgorithm = 'rsa-sha256'; if (!\defined('OPENSSL_ALGO_SHA256')) { throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.'); } break; default: throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash); } return $this; } /** * Set the body canonicalization algorithm. * * @param string $canon * * @return $this */ public function setBodyCanon($canon) { if ('relaxed' == $canon) { $this->bodyCanon = 'relaxed'; } else { $this->bodyCanon = 'simple'; } return $this; } /** * Set the header canonicalization algorithm. * * @param string $canon * * @return $this */ public function setHeaderCanon($canon) { if ('relaxed' == $canon) { $this->headerCanon = 'relaxed'; } else { $this->headerCanon = 'simple'; } return $this; } /** * Set the signer identity. * * @param string $identity * * @return $this */ public function setSignerIdentity($identity) { $this->signerIdentity = $identity; return $this; } /** * Set the length of the body to sign. * * @param mixed $len (bool or int) * * @return $this */ public function setBodySignedLen($len) { if (true === $len) { $this->showLen = true; $this->maxLen = PHP_INT_MAX; } elseif (false === $len) { $this->showLen = false; $this->maxLen = PHP_INT_MAX; } else { $this->showLen = true; $this->maxLen = (int) $len; } return $this; } /** * Set the signature timestamp. * * @param int $time A timestamp * * @return $this */ public function setSignatureTimestamp($time) { $this->signatureTimestamp = $time; return $this; } /** * Set the signature expiration timestamp. * * @param int $time A timestamp * * @return $this */ public function setSignatureExpiration($time) { $this->signatureExpiration = $time; return $this; } /** * Enable / disable the DebugHeaders. * * @param bool $debug * * @return Swift_Signers_DKIMSigner */ public function setDebugHeaders($debug) { $this->debugHeaders = (bool) $debug; return $this; } /** * Start Body. */ public function startBody() { // Init switch ($this->hashAlgorithm) { case 'rsa-sha256': $this->bodyHashHandler = hash_init('sha256'); break; case 'rsa-sha1': $this->bodyHashHandler = hash_init('sha1'); break; } $this->bodyCanonLine = ''; } /** * End Body. */ public function endBody() { $this->endOfBody(); } /** * Returns the list of Headers Tampered by this plugin. * * @return array */ public function getAlteredHeaders() { if ($this->debugHeaders) { return ['DKIM-Signature', 'X-DebugHash']; } else { return ['DKIM-Signature']; } } /** * Adds an ignored Header. * * @param string $header_name * * @return Swift_Signers_DKIMSigner */ public function ignoreHeader($header_name) { $this->ignoredHeaders[strtolower($header_name ?? '')] = true; return $this; } /** * Set the headers to sign. * * @return Swift_Signers_DKIMSigner */ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers) { $this->headerCanonData = ''; // Loop through Headers $listHeaders = $headers->listAll(); foreach ($listHeaders as $hName) { // Check if we need to ignore Header if (!isset($this->ignoredHeaders[strtolower($hName ?? '')])) { if ($headers->has($hName)) { $tmp = $headers->getAll($hName); foreach ($tmp as $header) { if ('' != $header->getFieldBody()) { $this->addHeader($header->toString()); $this->signedHeaders[] = $header->getFieldName(); } } } } } return $this; } /** * Add the signature to the given Headers. * * @return Swift_Signers_DKIMSigner */ public function addSignature(Swift_Mime_SimpleHeaderSet $headers) { // Prepare the DKIM-Signature $params = ['v' => '1', 'a' => $this->hashAlgorithm, 'bh' => base64_encode($this->bodyHash ?? ''), 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'i' => $this->signerIdentity, 's' => $this->selector]; if ('simple' != $this->bodyCanon) { $params['c'] = $this->headerCanon.'/'.$this->bodyCanon; } elseif ('simple' != $this->headerCanon) { $params['c'] = $this->headerCanon; } if ($this->showLen) { $params['l'] = $this->bodyLen; } if (true === $this->signatureTimestamp) { $params['t'] = time(); if (false !== $this->signatureExpiration) { $params['x'] = $params['t'] + $this->signatureExpiration; } } else { if (false !== $this->signatureTimestamp) { $params['t'] = $this->signatureTimestamp; } if (false !== $this->signatureExpiration) { $params['x'] = $this->signatureExpiration; } } if ($this->debugHeaders) { $params['z'] = implode('|', $this->debugHeadersData); } $string = ''; foreach ($params as $k => $v) { $string .= $k.'='.$v.'; '; } $string = trim($string); $headers->addTextHeader('DKIM-Signature', $string); // Add the last DKIM-Signature $tmp = $headers->getAll('DKIM-Signature'); $this->dkimHeader = end($tmp); $this->addHeader(trim($this->dkimHeader->toString() ?? '')."\r\n b=", true); if ($this->debugHeaders) { $headers->addTextHeader('X-DebugHash', base64_encode($this->headerHash ?? '')); } $this->dkimHeader->setValue($string.' b='.trim(chunk_split(base64_encode($this->getEncryptedHash() ?? ''), 73, ' '))); return $this; } /* Private helpers */ protected function addHeader($header, $is_sig = false) { switch ($this->headerCanon) { case 'relaxed': // Prepare Header and cascade $exploded = explode(':', $header, 2); $name = strtolower(trim($exploded[0])); $value = str_replace("\r\n", '', $exploded[1]); $value = preg_replace("/[ \t][ \t]+/", ' ', $value); $header = $name.':'.trim($value).($is_sig ? '' : "\r\n"); // no break case 'simple': // Nothing to do } $this->addToHeaderHash($header); } protected function canonicalizeBody($string) { $len = \strlen($string); $canon = ''; $method = ('relaxed' == $this->bodyCanon); for ($i = 0; $i < $len; ++$i) { if ($this->bodyCanonIgnoreStart > 0) { --$this->bodyCanonIgnoreStart; continue; } switch ($string[$i]) { case "\r": $this->bodyCanonLastChar = "\r"; break; case "\n": if ("\r" == $this->bodyCanonLastChar) { if ($method) { $this->bodyCanonSpace = false; } if ('' == $this->bodyCanonLine) { ++$this->bodyCanonEmptyCounter; } else { $this->bodyCanonLine = ''; $canon .= "\r\n"; } } else { // Wooops Error // todo handle it but should never happen } break; case ' ': case "\t": if ($method) { $this->bodyCanonSpace = true; break; } // no break default: if ($this->bodyCanonEmptyCounter > 0) { $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter); $this->bodyCanonEmptyCounter = 0; } if ($this->bodyCanonSpace) { $this->bodyCanonLine .= ' '; $canon .= ' '; $this->bodyCanonSpace = false; } $this->bodyCanonLine .= $string[$i]; $canon .= $string[$i]; } } $this->addToBodyHash($canon); } protected function endOfBody() { // Add trailing Line return if last line is non empty if (\strlen($this->bodyCanonLine) > 0) { $this->addToBodyHash("\r\n"); } $this->bodyHash = hash_final($this->bodyHashHandler, true); } private function addToBodyHash($string) { $len = \strlen($string); if ($len > ($new_len = ($this->maxLen - $this->bodyLen))) { $string = substr($string, 0, $new_len); $len = $new_len; } hash_update($this->bodyHashHandler, $string); $this->bodyLen += $len; } private function addToHeaderHash($header) { if ($this->debugHeaders) { $this->debugHeadersData[] = trim($header ?? ''); } $this->headerCanonData .= $header; } /** * @throws Swift_SwiftException * * @return string */ private function getEncryptedHash() { $signature = ''; switch ($this->hashAlgorithm) { case 'rsa-sha1': $algorithm = OPENSSL_ALGO_SHA1; break; case 'rsa-sha256': $algorithm = OPENSSL_ALGO_SHA256; break; } $pkeyId = openssl_get_privatekey($this->privateKey, $this->passphrase); if (!$pkeyId) { throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']'); } if (openssl_sign($this->headerCanonData, $signature, $pkeyId, $algorithm)) { return $signature; } throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']'); } } swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php 0000777 00000042717 14710744267 0016734 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * MIME Message Signer used to apply S/MIME Signature/Encryption to a message. * * @author Romain-Geissler * @author Sebastiaan Stok <s.stok@rollerscapes.net> * @author Jan Flora <jf@penneo.com> */ class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner { protected $signCertificate; protected $signPrivateKey; protected $encryptCert; protected $signThenEncrypt = true; protected $signLevel; protected $encryptLevel; protected $signOptions; protected $encryptOptions; protected $encryptCipher; protected $extraCerts = null; protected $wrapFullMessage = false; /** * @var Swift_StreamFilters_StringReplacementFilterFactory */ protected $replacementFactory; /** * @var Swift_Mime_SimpleHeaderFactory */ protected $headerFactory; /** * Constructor. * * @param string|null $signCertificate * @param string|null $signPrivateKey * @param string|null $encryptCertificate */ public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null) { if (null !== $signPrivateKey) { $this->setSignCertificate($signCertificate, $signPrivateKey); } if (null !== $encryptCertificate) { $this->setEncryptCertificate($encryptCertificate); } $this->replacementFactory = Swift_DependencyContainer::getInstance() ->lookup('transport.replacementfactory'); $this->signOptions = PKCS7_DETACHED; $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; } /** * Set the certificate location to use for signing. * * @see https://secure.php.net/manual/en/openssl.pkcs7.flags.php * * @param string $certificate * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign() * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate * * @return $this */ public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null) { $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate)); if (null !== $privateKey) { if (\is_array($privateKey)) { $this->signPrivateKey = $privateKey; $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0])); } else { $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey)); } } $this->signOptions = $signOptions; $this->extraCerts = $extraCerts ? realpath($extraCerts) : null; return $this; } /** * Set the certificate location to use for encryption. * * @see https://secure.php.net/manual/en/openssl.pkcs7.flags.php * @see https://secure.php.net/manual/en/openssl.ciphers.php * * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates. * @param int $cipher * * @return $this */ public function setEncryptCertificate($recipientCerts, $cipher = null) { if (\is_array($recipientCerts)) { $this->encryptCert = []; foreach ($recipientCerts as $cert) { $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert)); } } else { $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts)); } if (null !== $cipher) { $this->encryptCipher = $cipher; } return $this; } /** * @return string */ public function getSignCertificate() { return $this->signCertificate; } /** * @return string */ public function getSignPrivateKey() { return $this->signPrivateKey; } /** * Set perform signing before encryption. * * The default is to first sign the message and then encrypt. * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted. * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients. * * @param bool $signThenEncrypt * * @return $this */ public function setSignThenEncrypt($signThenEncrypt = true) { $this->signThenEncrypt = $signThenEncrypt; return $this; } /** * @return bool */ public function isSignThenEncrypt() { return $this->signThenEncrypt; } /** * Resets internal states. * * @return $this */ public function reset() { return $this; } /** * Specify whether to wrap the entire MIME message in the S/MIME message. * * According to RFC5751 section 3.1: * In order to protect outer, non-content-related message header fields * (for instance, the "Subject", "To", "From", and "Cc" fields), the * sending client MAY wrap a full MIME message in a message/rfc822 * wrapper in order to apply S/MIME security services to these header * fields. It is up to the receiving client to decide how to present * this "inner" header along with the unprotected "outer" header. * * @param bool $wrap * * @return $this */ public function setWrapFullMessage($wrap) { $this->wrapFullMessage = $wrap; } /** * Change the Swift_Message to apply the signing. * * @return $this */ public function signMessage(Swift_Message $message) { if (null === $this->signCertificate && null === $this->encryptCert) { return $this; } if ($this->signThenEncrypt) { $this->smimeSignMessage($message); $this->smimeEncryptMessage($message); } else { $this->smimeEncryptMessage($message); $this->smimeSignMessage($message); } } /** * Return the list of header a signer might tamper. * * @return array */ public function getAlteredHeaders() { return ['Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition']; } /** * Sign a Swift message. */ protected function smimeSignMessage(Swift_Message $message) { // If we don't have a certificate we can't sign the message if (null === $this->signCertificate) { return; } // Work on a clone of the original message $signMessage = clone $message; $signMessage->clearSigners(); if ($this->wrapFullMessage) { // The original message essentially becomes the body of the new // wrapped message $signMessage = $this->wrapMimeMessage($signMessage); } else { // Only keep header needed to parse the body correctly $this->clearAllHeaders($signMessage); $this->copyHeaders( $message, $signMessage, [ 'Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition', ] ); } // Copy the cloned message into a temporary file stream $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); $signMessage->toByteStream($messageStream); $messageStream->commit(); $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); // Sign the message using openssl if (!openssl_pkcs7_sign( $messageStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, [], $this->signOptions, $this->extraCerts ) ) { throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); } // Parse the resulting signed message content back into the Swift message // preserving the original headers $this->parseSSLOutput($signedMessageStream, $message); } /** * Encrypt a Swift message. */ protected function smimeEncryptMessage(Swift_Message $message) { // If we don't have a certificate we can't encrypt the message if (null === $this->encryptCert) { return; } // Work on a clone of the original message $encryptMessage = clone $message; $encryptMessage->clearSigners(); if ($this->wrapFullMessage) { // The original message essentially becomes the body of the new // wrapped message $encryptMessage = $this->wrapMimeMessage($encryptMessage); } else { // Only keep header needed to parse the body correctly $this->clearAllHeaders($encryptMessage); $this->copyHeaders( $message, $encryptMessage, [ 'Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition', ] ); } // Convert the message content (including headers) to a string // and place it in a temporary file $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); $encryptMessage->toByteStream($messageStream); $messageStream->commit(); $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); // Encrypt the message if (!openssl_pkcs7_encrypt( $messageStream->getPath(), $encryptedMessageStream->getPath(), $this->encryptCert, [], 0, $this->encryptCipher ) ) { throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); } // Parse the resulting signed message content back into the Swift message // preserving the original headers $this->parseSSLOutput($encryptedMessageStream, $message); } /** * Copy named headers from one Swift message to another. */ protected function copyHeaders( Swift_Message $fromMessage, Swift_Message $toMessage, array $headers = [] ) { foreach ($headers as $header) { $this->copyHeader($fromMessage, $toMessage, $header); } } /** * Copy a single header from one Swift message to another. * * @param string $headerName */ protected function copyHeader(Swift_Message $fromMessage, Swift_Message $toMessage, $headerName) { $header = $fromMessage->getHeaders()->get($headerName); if (!$header) { return; } $headers = $toMessage->getHeaders(); switch ($header->getFieldType()) { case Swift_Mime_Header::TYPE_TEXT: $headers->addTextHeader($header->getFieldName(), $header->getValue()); break; case Swift_Mime_Header::TYPE_PARAMETERIZED: $headers->addParameterizedHeader( $header->getFieldName(), $header->getValue(), $header->getParameters() ); break; } } /** * Remove all headers from a Swift message. */ protected function clearAllHeaders(Swift_Message $message) { $headers = $message->getHeaders(); foreach ($headers->listAll() as $header) { $headers->removeAll($header); } } /** * Wraps a Swift_Message in a message/rfc822 MIME part. * * @return Swift_MimePart */ protected function wrapMimeMessage(Swift_Message $message) { // Start by copying the original message into a message stream $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); $message->toByteStream($messageStream); $messageStream->commit(); // Create a new MIME part that wraps the original stream $wrappedMessage = new Swift_MimePart($messageStream, 'message/rfc822'); $wrappedMessage->setEncoder(new Swift_Mime_ContentEncoder_PlainContentEncoder('7bit')); return $wrappedMessage; } protected function parseSSLOutput(Swift_InputByteStream $inputStream, Swift_Message $message) { $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); $this->copyFromOpenSSLOutput($inputStream, $messageStream); $this->streamToMime($messageStream, $message); } /** * Merges an OutputByteStream from OpenSSL to a Swift_Message. */ protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message) { // Parse the stream into headers and body list($headers, $messageStream) = $this->parseStream($fromStream); // Get the original message headers $messageHeaders = $message->getHeaders(); // Let the stream determine the headers describing the body content, // since the body of the original message is overwritten by the body // coming from the stream. // These are all content-* headers. // Default transfer encoding is 7bit if not set $encoding = ''; // Remove all existing transfer encoding headers $messageHeaders->removeAll('Content-Transfer-Encoding'); // See whether the stream sets the transfer encoding if (isset($headers['content-transfer-encoding'])) { $encoding = $headers['content-transfer-encoding']; } // We use the null content encoder, since the body is already encoded // according to the transfer encoding specified in the stream $message->setEncoder(new Swift_Mime_ContentEncoder_NullContentEncoder($encoding)); // Set the disposition, if present if (isset($headers['content-disposition'])) { $messageHeaders->addTextHeader('Content-Disposition', $headers['content-disposition']); } // Copy over the body from the stream using the content type dictated // by the stream content $message->setChildren([]); $message->setBody($messageStream, $headers['content-type']); } /** * This message will parse the headers of a MIME email byte stream * and return an array that contains the headers as an associative * array and the email body as a string. * * @return array */ protected function parseStream(Swift_OutputByteStream $emailStream) { $bufferLength = 78; $headerData = ''; $headerBodySeparator = "\r\n\r\n"; $emailStream->setReadPointer(0); // Read out the headers section from the stream to a string while (false !== ($buffer = $emailStream->read($bufferLength))) { $headerData .= $buffer; $headersPosEnd = strpos($headerData, $headerBodySeparator); // Stop reading if we found the end of the headers if (false !== $headersPosEnd) { break; } } // Split the header data into lines $headerData = trim(substr($headerData, 0, $headersPosEnd)); $headerLines = explode("\r\n", $headerData); unset($headerData); $headers = []; $currentHeaderName = ''; // Transform header lines into an associative array foreach ($headerLines as $headerLine) { // Handle headers that span multiple lines if (false === strpos($headerLine, ':')) { $headers[$currentHeaderName] .= ' '.trim($headerLine ?? ''); continue; } $header = explode(':', $headerLine, 2); $currentHeaderName = strtolower($header[0] ?? ''); $headers[$currentHeaderName] = trim($header[1] ?? ''); } // Read the entire email body into a byte stream $bodyStream = new Swift_ByteStream_TemporaryFileByteStream(); // Skip the header and separator and point to the body $emailStream->setReadPointer($headersPosEnd + \strlen($headerBodySeparator)); while (false !== ($buffer = $emailStream->read($bufferLength))) { $bodyStream->write($buffer); } $bodyStream->commit(); return [$headers, $bodyStream]; } protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream) { $bufferLength = 4096; $filteredStream = new Swift_ByteStream_TemporaryFileByteStream(); $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); while (false !== ($buffer = $fromStream->read($bufferLength))) { $filteredStream->write($buffer); } $filteredStream->flushBuffers(); while (false !== ($buffer = $filteredStream->read($bufferLength))) { $toStream->write($buffer); } $toStream->commit(); } } swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php 0000777 00000027455 14710744267 0017604 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * DomainKey Signer used to apply DomainKeys Signature to a message. * * @author Xavier De Cock <xdecock@gmail.com> */ class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner { /** * PrivateKey. * * @var string */ protected $privateKey; /** * DomainName. * * @var string */ protected $domainName; /** * Selector. * * @var string */ protected $selector; /** * Hash algorithm used. * * @var string */ protected $hashAlgorithm = 'rsa-sha1'; /** * Canonisation method. * * @var string */ protected $canon = 'simple'; /** * Headers not being signed. * * @var array */ protected $ignoredHeaders = []; /** * Signer identity. * * @var string */ protected $signerIdentity; /** * Must we embed signed headers? * * @var bool */ protected $debugHeaders = false; // work variables /** * Headers used to generate hash. * * @var array */ private $signedHeaders = []; /** * Stores the signature header. * * @var Swift_Mime_Headers_ParameterizedHeader */ protected $domainKeyHeader; /** * Hash Handler. * * @var resource|null */ private $hashHandler; private $canonData = ''; private $bodyCanonEmptyCounter = 0; private $bodyCanonIgnoreStart = 2; private $bodyCanonSpace = false; private $bodyCanonLastChar = null; private $bodyCanonLine = ''; private $bound = []; /** * Constructor. * * @param string $privateKey * @param string $domainName * @param string $selector */ public function __construct($privateKey, $domainName, $selector) { $this->privateKey = $privateKey; $this->domainName = $domainName; $this->signerIdentity = '@'.$domainName; $this->selector = $selector; } /** * Resets internal states. * * @return $this */ public function reset() { $this->hashHandler = null; $this->bodyCanonIgnoreStart = 2; $this->bodyCanonEmptyCounter = 0; $this->bodyCanonLastChar = null; $this->bodyCanonSpace = false; return $this; } /** * Writes $bytes to the end of the stream. * * Writing may not happen immediately if the stream chooses to buffer. If * you want to write these bytes with immediate effect, call {@link commit()} * after calling write(). * * This method returns the sequence ID of the write (i.e. 1 for first, 2 for * second, etc etc). * * @param string $bytes * * @return int * * @throws Swift_IoException * * @return $this */ public function write($bytes) { $this->canonicalizeBody($bytes); foreach ($this->bound as $is) { $is->write($bytes); } return $this; } /** * For any bytes that are currently buffered inside the stream, force them * off the buffer. * * @throws Swift_IoException * * @return $this */ public function commit() { // Nothing to do return $this; } /** * Attach $is to this stream. * * The stream acts as an observer, receiving all data that is written. * All {@link write()} and {@link flushBuffers()} operations will be mirrored. * * @return $this */ public function bind(Swift_InputByteStream $is) { // Don't have to mirror anything $this->bound[] = $is; return $this; } /** * Remove an already bound stream. * * If $is is not bound, no errors will be raised. * If the stream currently has any buffered data it will be written to $is * before unbinding occurs. * * @return $this */ public function unbind(Swift_InputByteStream $is) { // Don't have to mirror anything foreach ($this->bound as $k => $stream) { if ($stream === $is) { unset($this->bound[$k]); break; } } return $this; } /** * Flush the contents of the stream (empty it) and set the internal pointer * to the beginning. * * @throws Swift_IoException * * @return $this */ public function flushBuffers() { $this->reset(); return $this; } /** * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256. * * @param string $hash * * @return $this */ public function setHashAlgorithm($hash) { $this->hashAlgorithm = 'rsa-sha1'; return $this; } /** * Set the canonicalization algorithm. * * @param string $canon simple | nofws defaults to simple * * @return $this */ public function setCanon($canon) { if ('nofws' == $canon) { $this->canon = 'nofws'; } else { $this->canon = 'simple'; } return $this; } /** * Set the signer identity. * * @param string $identity * * @return $this */ public function setSignerIdentity($identity) { $this->signerIdentity = $identity; return $this; } /** * Enable / disable the DebugHeaders. * * @param bool $debug * * @return $this */ public function setDebugHeaders($debug) { $this->debugHeaders = (bool) $debug; return $this; } /** * Start Body. */ public function startBody() { } /** * End Body. */ public function endBody() { $this->endOfBody(); } /** * Returns the list of Headers Tampered by this plugin. * * @return array */ public function getAlteredHeaders() { if ($this->debugHeaders) { return ['DomainKey-Signature', 'X-DebugHash']; } return ['DomainKey-Signature']; } /** * Adds an ignored Header. * * @param string $header_name * * @return $this */ public function ignoreHeader($header_name) { $this->ignoredHeaders[strtolower($header_name ?? '')] = true; return $this; } /** * Set the headers to sign. * * @return $this */ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers) { $this->startHash(); $this->canonData = ''; // Loop through Headers $listHeaders = $headers->listAll(); foreach ($listHeaders as $hName) { // Check if we need to ignore Header if (!isset($this->ignoredHeaders[strtolower($hName ?? '')])) { if ($headers->has($hName)) { $tmp = $headers->getAll($hName); foreach ($tmp as $header) { if ('' != $header->getFieldBody()) { $this->addHeader($header->toString()); $this->signedHeaders[] = $header->getFieldName(); } } } } } $this->endOfHeaders(); return $this; } /** * Add the signature to the given Headers. * * @return $this */ public function addSignature(Swift_Mime_SimpleHeaderSet $headers) { // Prepare the DomainKey-Signature Header $params = ['a' => $this->hashAlgorithm, 'b' => chunk_split(base64_encode($this->getEncryptedHash() ?? ''), 73, ' '), 'c' => $this->canon, 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'q' => 'dns', 's' => $this->selector]; $string = ''; foreach ($params as $k => $v) { $string .= $k.'='.$v.'; '; } $string = trim($string); $headers->addTextHeader('DomainKey-Signature', $string); return $this; } /* Private helpers */ protected function addHeader($header) { switch ($this->canon) { case 'nofws': // Prepare Header and cascade $exploded = explode(':', $header, 2); $name = strtolower(trim($exploded[0])); $value = str_replace("\r\n", '', $exploded[1]); $value = preg_replace("/[ \t][ \t]+/", ' ', $value); $header = $name.':'.trim($value)."\r\n"; // no break case 'simple': // Nothing to do } $this->addToHash($header); } protected function endOfHeaders() { $this->bodyCanonEmptyCounter = 1; } protected function canonicalizeBody($string) { $len = \strlen($string); $canon = ''; $nofws = ('nofws' == $this->canon); for ($i = 0; $i < $len; ++$i) { if ($this->bodyCanonIgnoreStart > 0) { --$this->bodyCanonIgnoreStart; continue; } switch ($string[$i]) { case "\r": $this->bodyCanonLastChar = "\r"; break; case "\n": if ("\r" == $this->bodyCanonLastChar) { if ($nofws) { $this->bodyCanonSpace = false; } if ('' == $this->bodyCanonLine) { ++$this->bodyCanonEmptyCounter; } else { $this->bodyCanonLine = ''; $canon .= "\r\n"; } } else { // Wooops Error throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r'); } break; case ' ': case "\t": case "\x09": //HTAB if ($nofws) { $this->bodyCanonSpace = true; break; } // no break default: if ($this->bodyCanonEmptyCounter > 0) { $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter); $this->bodyCanonEmptyCounter = 0; } $this->bodyCanonLine .= $string[$i]; $canon .= $string[$i]; } } $this->addToHash($canon); } protected function endOfBody() { if (\strlen($this->bodyCanonLine) > 0) { $this->addToHash("\r\n"); } } private function addToHash($string) { $this->canonData .= $string; hash_update($this->hashHandler, $string); } private function startHash() { // Init switch ($this->hashAlgorithm) { case 'rsa-sha1': $this->hashHandler = hash_init('sha1'); break; } $this->bodyCanonLine = ''; } /** * @throws Swift_SwiftException * * @return string */ private function getEncryptedHash() { $signature = ''; $pkeyId = openssl_get_privatekey($this->privateKey); if (!$pkeyId) { throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']'); } if (openssl_sign($this->canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) { return $signature; } throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']'); } } swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php 0000777 00000012026 14710744267 0017256 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * DKIM Signer used to apply DKIM Signature to a message * Takes advantage of pecl extension. * * @author Xavier De Cock <xdecock@gmail.com> * * @deprecated since SwiftMailer 6.1.0; use Swift_Signers_DKIMSigner instead. */ class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner { private $peclLoaded = false; private $dkimHandler = null; private $dropFirstLF = true; const CANON_RELAXED = 1; const CANON_SIMPLE = 2; const SIG_RSA_SHA1 = 3; const SIG_RSA_SHA256 = 4; public function __construct($privateKey, $domainName, $selector) { if (!\extension_loaded('opendkim')) { throw new Swift_SwiftException('php-opendkim extension not found'); } $this->peclLoaded = true; parent::__construct($privateKey, $domainName, $selector); } public function addSignature(Swift_Mime_SimpleHeaderSet $headers) { $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature'); $headerVal = $this->dkimHandler->getSignatureHeader(); if (false === $headerVal || \is_int($headerVal)) { throw new Swift_SwiftException('OpenDKIM Error: '.$this->dkimHandler->getError()); } $header->setValue($headerVal); $headers->set($header); return $this; } public function setHeaders(Swift_Mime_SimpleHeaderSet $headers) { $hash = 'rsa-sha1' == $this->hashAlgorithm ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256; $bodyCanon = 'simple' == $this->bodyCanon ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; $headerCanon = 'simple' == $this->headerCanon ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; $this->dkimHandler = new OpenDKIMSign($this->privateKey, $this->selector, $this->domainName, $headerCanon, $bodyCanon, $hash, -1); // Hardcode signature Margin for now $this->dkimHandler->setMargin(78); if (!is_numeric($this->signatureTimestamp)) { OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time()); } else { if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->signatureTimestamp)) { throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']'); } } if (isset($this->signerIdentity)) { $this->dkimHandler->setSigner($this->signerIdentity); } $listHeaders = $headers->listAll(); foreach ($listHeaders as $hName) { // Check if we need to ignore Header if (!isset($this->ignoredHeaders[strtolower($hName ?? '')])) { $tmp = $headers->getAll($hName); if ($headers->has($hName)) { foreach ($tmp as $header) { if ('' != $header->getFieldBody()) { $htosign = $header->toString(); $this->dkimHandler->header($htosign); $this->signedHeaders[] = $header->getFieldName(); } } } } } return $this; } public function startBody() { if (!$this->peclLoaded) { return parent::startBody(); } $this->dropFirstLF = true; $this->dkimHandler->eoh(); return $this; } public function endBody() { if (!$this->peclLoaded) { return parent::endBody(); } $this->dkimHandler->eom(); return $this; } public function reset() { $this->dkimHandler = null; parent::reset(); return $this; } /** * Set the signature timestamp. * * @param int $time * * @return $this */ public function setSignatureTimestamp($time) { $this->signatureTimestamp = $time; return $this; } /** * Set the signature expiration timestamp. * * @param int $time * * @return $this */ public function setSignatureExpiration($time) { $this->signatureExpiration = $time; return $this; } /** * Enable / disable the DebugHeaders. * * @param bool $debug * * @return $this */ public function setDebugHeaders($debug) { $this->debugHeaders = (bool) $debug; return $this; } // Protected protected function canonicalizeBody($string) { if (!$this->peclLoaded) { return parent::canonicalizeBody($string); } if (true === $this->dropFirstLF) { if ("\r" == $string[0] && "\n" == $string[1]) { $string = substr($string, 2); } } $this->dropFirstLF = false; if (\strlen($string)) { $this->dkimHandler->body($string); } } } swiftmailer/lib/classes/Swift/Transport.php 0000777 00000003736 14710744267 0015132 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Sends Messages via an abstract Transport subsystem. * * @author Chris Corbyn */ interface Swift_Transport { /** * Test if this Transport mechanism has started. * * @return bool */ public function isStarted(); /** * Start this Transport mechanism. */ public function start(); /** * Stop this Transport mechanism. */ public function stop(); /** * Check if this Transport mechanism is alive. * * If a Transport mechanism session is no longer functional, the method * returns FALSE. It is the responsibility of the developer to handle this * case and restart the Transport mechanism manually. * * @example * * if (!$transport->ping()) { * $transport->stop(); * $transport->start(); * } * * The Transport mechanism will be started, if it is not already. * * It is undefined if the Transport mechanism attempts to restart as long as * the return value reflects whether the mechanism is now functional. * * @return bool TRUE if the transport is alive */ public function ping(); /** * Send the given Message. * * Recipient/sender data will be retrieved from the Message API. * The return value is the number of recipients who were accepted for delivery. * * This is the responsibility of the send method to start the transport if needed. * * @param string[] $failedRecipients An array of failures by-reference * * @return int */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null); /** * Register a plugin in the Transport. */ public function registerPlugin(Swift_Events_EventListener $plugin); } swiftmailer/lib/classes/Swift/RfcComplianceException.php 0000777 00000001052 14710744267 0017507 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * RFC Compliance Exception class. * * @author Chris Corbyn */ class Swift_RfcComplianceException extends Swift_SwiftException { /** * Create a new RfcComplianceException with $message. * * @param string $message */ public function __construct($message) { parent::__construct($message); } } swiftmailer/lib/classes/Swift/FileStream.php 0000777 00000000750 14710744267 0015162 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An OutputByteStream which specifically reads from a file. * * @author Chris Corbyn */ interface Swift_FileStream extends Swift_OutputByteStream { /** * Get the complete path to the file. * * @return string */ public function getPath(); } swiftmailer/lib/classes/Swift/MemorySpool.php 0000777 00000005310 14710744267 0015411 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2011 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Stores Messages in memory. * * @author Fabien Potencier */ class Swift_MemorySpool implements Swift_Spool { protected $messages = []; private $flushRetries = 3; /** * Tests if this Transport mechanism has started. * * @return bool */ public function isStarted() { return true; } /** * Starts this Transport mechanism. */ public function start() { } /** * Stops this Transport mechanism. */ public function stop() { } /** * @param int $retries */ public function setFlushRetries($retries) { $this->flushRetries = $retries; } /** * Stores a message in the queue. * * @param Swift_Mime_SimpleMessage $message The message to store * * @return bool Whether the operation has succeeded */ public function queueMessage(Swift_Mime_SimpleMessage $message) { //clone the message to make sure it is not changed while in the queue $this->messages[] = clone $message; return true; } /** * Sends messages using the given transport instance. * * @param Swift_Transport $transport A transport instance * @param string[] $failedRecipients An array of failures by-reference * * @return int The number of sent emails */ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) { if (!$this->messages) { return 0; } if (!$transport->isStarted()) { $transport->start(); } $count = 0; $retries = $this->flushRetries; while ($retries--) { try { while ($message = array_pop($this->messages)) { $count += $transport->send($message, $failedRecipients); } } catch (Swift_TransportException $exception) { if ($retries) { // re-queue the message at the end of the queue to give a chance // to the other messages to be sent, in case the failure was due to // this message and not just the transport failing array_unshift($this->messages, $message); // wait half a second before we try again usleep(500000); } else { throw $exception; } } } return $count; } } swiftmailer/lib/classes/Swift/SwiftException.php 0000777 00000001131 14710744267 0016074 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Base Exception class. * * @author Chris Corbyn */ class Swift_SwiftException extends Exception { /** * Create a new SwiftException with $message. * * @param string $message * @param int $code */ public function __construct($message, $code = 0, Exception $previous = null) { parent::__construct($message, $code, $previous); } } swiftmailer/lib/classes/Swift/Attachment.php 0000777 00000002651 14710744267 0015221 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Attachment class for attaching files to a {@link Swift_Mime_SimpleMessage}. * * @author Chris Corbyn */ class Swift_Attachment extends Swift_Mime_Attachment { /** * Create a new Attachment. * * Details may be optionally provided to the constructor. * * @param string|Swift_OutputByteStream $data * @param string $filename * @param string $contentType */ public function __construct($data = null, $filename = null, $contentType = null) { \call_user_func_array( [$this, 'Swift_Mime_Attachment::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('mime.attachment') ); $this->setBody($data, $contentType); $this->setFilename($filename); } /** * Create a new Attachment from a filesystem path. * * @param string $path * @param string $contentType optional * * @return self */ public static function fromPath($path, $contentType = null) { return (new self())->setFile( new Swift_ByteStream_FileByteStream($path), $contentType ); } } swiftmailer/lib/classes/Swift/SendmailTransport.php 0000777 00000001566 14710744267 0016606 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * SendmailTransport for sending mail through a Sendmail/Postfix (etc..) binary. * * @author Chris Corbyn */ class Swift_SendmailTransport extends Swift_Transport_SendmailTransport { /** * Create a new SendmailTransport, optionally using $command for sending. * * @param string $command */ public function __construct($command = '/usr/sbin/sendmail -bs') { \call_user_func_array( [$this, 'Swift_Transport_SendmailTransport::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('transport.sendmail') ); $this->setCommand($command); } } swiftmailer/lib/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php 0000777 00000006330 14710744267 0025217 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Standard factory for creating CharacterReaders. * * @author Chris Corbyn */ class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory implements Swift_CharacterReaderFactory { /** * A map of charset patterns to their implementation classes. * * @var array */ private static $map = []; /** * Factories which have already been loaded. * * @var Swift_CharacterReaderFactory[] */ private static $loaded = []; /** * Creates a new CharacterReaderFactory. */ public function __construct() { $this->init(); } public function __wakeup() { $this->init(); } public function init() { if (\count(self::$map) > 0) { return; } $prefix = 'Swift_CharacterReader_'; $singleByte = [ 'class' => $prefix.'GenericFixedWidthReader', 'constructor' => [1], ]; $doubleByte = [ 'class' => $prefix.'GenericFixedWidthReader', 'constructor' => [2], ]; $fourBytes = [ 'class' => $prefix.'GenericFixedWidthReader', 'constructor' => [4], ]; // Utf-8 self::$map['utf-?8'] = [ 'class' => $prefix.'Utf8Reader', 'constructor' => [], ]; //7-8 bit charsets self::$map['(us-)?ascii'] = $singleByte; self::$map['(iso|iec)-?8859-?[0-9]+'] = $singleByte; self::$map['windows-?125[0-9]'] = $singleByte; self::$map['cp-?[0-9]+'] = $singleByte; self::$map['ansi'] = $singleByte; self::$map['macintosh'] = $singleByte; self::$map['koi-?7'] = $singleByte; self::$map['koi-?8-?.+'] = $singleByte; self::$map['mik'] = $singleByte; self::$map['(cork|t1)'] = $singleByte; self::$map['v?iscii'] = $singleByte; //16 bits self::$map['(ucs-?2|utf-?16)'] = $doubleByte; //32 bits self::$map['(ucs-?4|utf-?32)'] = $fourBytes; // Fallback self::$map['.*'] = $singleByte; } /** * Returns a CharacterReader suitable for the charset applied. * * @param string $charset * * @return Swift_CharacterReader */ public function getReaderFor($charset) { $charset = strtolower(trim($charset ?? '')); foreach (self::$map as $pattern => $spec) { $re = '/^'.$pattern.'$/D'; if (preg_match($re, $charset)) { if (!\array_key_exists($pattern, self::$loaded)) { $reflector = new ReflectionClass($spec['class']); if ($reflector->getConstructor()) { $reader = $reflector->newInstanceArgs($spec['constructor']); } else { $reader = $reflector->newInstance(); } self::$loaded[$pattern] = $reader; } return self::$loaded[$pattern]; } } } } swiftmailer/lib/classes/Swift/EmbeddedFile.php 0000777 00000002577 14710744267 0015431 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An embedded file, in a multipart message. * * @author Chris Corbyn */ class Swift_EmbeddedFile extends Swift_Mime_EmbeddedFile { /** * Create a new EmbeddedFile. * * Details may be optionally provided to the constructor. * * @param string|Swift_OutputByteStream $data * @param string $filename * @param string $contentType */ public function __construct($data = null, $filename = null, $contentType = null) { \call_user_func_array( [$this, 'Swift_Mime_EmbeddedFile::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('mime.embeddedfile') ); $this->setBody($data); $this->setFilename($filename); if ($contentType) { $this->setContentType($contentType); } } /** * Create a new EmbeddedFile from a filesystem path. * * @param string $path * * @return Swift_Mime_EmbeddedFile */ public static function fromPath($path) { return (new self())->setFile(new Swift_ByteStream_FileByteStream($path)); } } swiftmailer/lib/classes/Swift/LoadBalancedTransport.php 0000777 00000001556 14710744267 0017342 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Redundantly and rotationally uses several Transport implementations when sending. * * @author Chris Corbyn */ class Swift_LoadBalancedTransport extends Swift_Transport_LoadBalancedTransport { /** * Creates a new LoadBalancedTransport with $transports. * * @param array $transports */ public function __construct($transports = []) { \call_user_func_array( [$this, 'Swift_Transport_LoadBalancedTransport::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('transport.loadbalanced') ); $this->setTransports($transports); } } swiftmailer/lib/classes/Swift/Transport/IoBuffer.php 0000777 00000003144 14710744267 0016624 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Buffers input and output to a resource. * * @author Chris Corbyn */ interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream { /** A socket buffer over TCP */ const TYPE_SOCKET = 0x0001; /** A process buffer with I/O support */ const TYPE_PROCESS = 0x0010; /** * Perform any initialization needed, using the given $params. * * Parameters will vary depending upon the type of IoBuffer used. */ public function initialize(array $params); /** * Set an individual param on the buffer (e.g. switching to SSL). * * @param string $param * @param mixed $value */ public function setParam($param, $value); /** * Perform any shutdown logic needed. */ public function terminate(); /** * Set an array of string replacements which should be made on data written * to the buffer. * * This could replace LF with CRLF for example. * * @param string[] $replacements */ public function setWriteTranslations(array $replacements); /** * Get a line of output (including any CRLF). * * The $sequence number comes from any writes and may or may not be used * depending upon the implementation. * * @param int $sequence of last write to scan from * * @return string */ public function readLine($sequence); } swiftmailer/lib/classes/Swift/Transport/NullTransport.php 0000777 00000004250 14710744267 0017751 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Pretends messages have been sent, but just ignores them. * * @author Fabien Potencier */ class Swift_Transport_NullTransport implements Swift_Transport { /** The event dispatcher from the plugin API */ private $eventDispatcher; /** * Constructor. */ public function __construct(Swift_Events_EventDispatcher $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; } /** * Tests if this Transport mechanism has started. * * @return bool */ public function isStarted() { return true; } /** * Starts this Transport mechanism. */ public function start() { } /** * Stops this Transport mechanism. */ public function stop() { } /** * {@inheritdoc} */ public function ping() { return true; } /** * Sends the given message. * * @param string[] $failedRecipients An array of failures by-reference * * @return int The number of sent emails */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); if ($evt->bubbleCancelled()) { return 0; } } if ($evt) { $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); } $count = ( \count((array) $message->getTo()) + \count((array) $message->getCc()) + \count((array) $message->getBcc()) ); return $count; } /** * Register a plugin. */ public function registerPlugin(Swift_Events_EventListener $plugin) { $this->eventDispatcher->bindEventListener($plugin); } } swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php 0000777 00000022672 14710744267 0017517 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A generic IoBuffer implementation supporting remote sockets and local processes. * * @author Chris Corbyn */ class Swift_Transport_StreamBuffer extends Swift_ByteStream_AbstractFilterableInputStream implements Swift_Transport_IoBuffer { /** A primary socket */ private $stream; /** The input stream */ private $in; /** The output stream */ private $out; /** Buffer initialization parameters */ private $params = []; /** The ReplacementFilterFactory */ private $replacementFactory; /** Translations performed on data being streamed into the buffer */ private $translations = []; /** * Create a new StreamBuffer using $replacementFactory for transformations. */ public function __construct(Swift_ReplacementFilterFactory $replacementFactory) { $this->replacementFactory = $replacementFactory; } /** * Perform any initialization needed, using the given $params. * * Parameters will vary depending upon the type of IoBuffer used. */ public function initialize(array $params) { $this->params = $params; switch ($params['type']) { case self::TYPE_PROCESS: $this->establishProcessConnection(); break; case self::TYPE_SOCKET: default: $this->establishSocketConnection(); break; } } /** * Set an individual param on the buffer (e.g. switching to SSL). * * @param string $param * @param mixed $value */ public function setParam($param, $value) { if (isset($this->stream)) { switch ($param) { case 'timeout': if ($this->stream) { stream_set_timeout($this->stream, $value); } break; case 'blocking': if ($this->stream) { stream_set_blocking($this->stream, 1); } } } $this->params[$param] = $value; } public function startTLS() { // STREAM_CRYPTO_METHOD_TLS_CLIENT only allow tls1.0 connections (some php versions) // To support modern tls we allow explicit tls1.0, tls1.1, tls1.2 // Ssl3 and older are not allowed because they are vulnerable // @TODO make tls arguments configurable return stream_socket_enable_crypto($this->stream, true, STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT); } /** * Perform any shutdown logic needed. */ public function terminate() { if (isset($this->stream)) { switch ($this->params['type']) { case self::TYPE_PROCESS: fclose($this->in); fclose($this->out); proc_close($this->stream); break; case self::TYPE_SOCKET: default: fclose($this->stream); break; } } $this->stream = null; $this->out = null; $this->in = null; } /** * Set an array of string replacements which should be made on data written * to the buffer. * * This could replace LF with CRLF for example. * * @param string[] $replacements */ public function setWriteTranslations(array $replacements) { foreach ($this->translations as $search => $replace) { if (!isset($replacements[$search])) { $this->removeFilter($search); unset($this->translations[$search]); } } foreach ($replacements as $search => $replace) { if (!isset($this->translations[$search])) { $this->addFilter( $this->replacementFactory->createFilter($search, $replace), $search ); $this->translations[$search] = true; } } } /** * Get a line of output (including any CRLF). * * The $sequence number comes from any writes and may or may not be used * depending upon the implementation. * * @param int $sequence of last write to scan from * * @return string * * @throws Swift_IoException */ public function readLine($sequence) { if (isset($this->out) && !feof($this->out)) { $line = fgets($this->out); if (0 == \strlen($line)) { $metas = stream_get_meta_data($this->out); if ($metas['timed_out']) { throw new Swift_IoException('Connection to '.$this->getReadConnectionDescription().' Timed Out'); } } return $line; } } /** * Reads $length bytes from the stream into a string and moves the pointer * through the stream by $length. * * If less bytes exist than are requested the remaining bytes are given instead. * If no bytes are remaining at all, boolean false is returned. * * @param int $length * * @return string|bool * * @throws Swift_IoException */ public function read($length) { if (isset($this->out) && !feof($this->out)) { $ret = fread($this->out, $length); if (0 == \strlen($ret)) { $metas = stream_get_meta_data($this->out); if ($metas['timed_out']) { throw new Swift_IoException('Connection to '.$this->getReadConnectionDescription().' Timed Out'); } } return $ret; } } /** Not implemented */ public function setReadPointer($byteOffset) { } /** Flush the stream contents */ protected function flush() { if (isset($this->in)) { fflush($this->in); } } /** Write this bytes to the stream */ protected function doCommit($bytes) { if (isset($this->in)) { $bytesToWrite = \strlen($bytes); $totalBytesWritten = 0; while ($totalBytesWritten < $bytesToWrite) { $bytesWritten = fwrite($this->in, substr($bytes, $totalBytesWritten)); if (false === $bytesWritten || 0 === $bytesWritten) { break; } $totalBytesWritten += $bytesWritten; } if ($totalBytesWritten > 0) { return ++$this->sequence; } } } /** * Establishes a connection to a remote server. */ private function establishSocketConnection() { $host = $this->params['host']; if (!empty($this->params['protocol'])) { $host = $this->params['protocol'].'://'.$host; } $timeout = 15; if (!empty($this->params['timeout'])) { $timeout = $this->params['timeout']; } $options = []; if (!empty($this->params['sourceIp'])) { $options['socket']['bindto'] = $this->params['sourceIp'].':0'; } if (isset($this->params['stream_context_options'])) { $options = array_merge($options, $this->params['stream_context_options']); } $streamContext = stream_context_create($options); set_error_handler(function ($type, $msg) { throw new Swift_TransportException('Connection could not be established with host '.$this->params['host'].' :'.$msg); }); try { $this->stream = stream_socket_client($host.':'.$this->params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext); } finally { restore_error_handler(); } if (!empty($this->params['blocking'])) { stream_set_blocking($this->stream, 1); } else { stream_set_blocking($this->stream, 0); } stream_set_timeout($this->stream, $timeout); $this->in = &$this->stream; $this->out = &$this->stream; } /** * Opens a process for input/output. */ private function establishProcessConnection() { $command = $this->params['command']; $descriptorSpec = [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w'], ]; $pipes = []; $this->stream = proc_open($command, $descriptorSpec, $pipes); stream_set_blocking($pipes[2], 0); if ($err = stream_get_contents($pipes[2])) { throw new Swift_TransportException('Process could not be started ['.$err.']'); } $this->in = &$pipes[0]; $this->out = &$pipes[1]; } private function getReadConnectionDescription() { switch ($this->params['type']) { case self::TYPE_PROCESS: return 'Process '.$this->params['command']; break; case self::TYPE_SOCKET: default: $host = $this->params['host']; if (!empty($this->params['protocol'])) { $host = $this->params['protocol'].'://'.$host; } $host .= ':'.$this->params['port']; return $host; break; } } } swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php 0000777 00000004421 14710744267 0017510 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An ESMTP handler. * * @author Chris Corbyn */ interface Swift_Transport_EsmtpHandler { /** * Get the name of the ESMTP extension this handles. * * @return string */ public function getHandledKeyword(); /** * Set the parameters which the EHLO greeting indicated. * * @param string[] $parameters */ public function setKeywordParams(array $parameters); /** * Runs immediately after a EHLO has been issued. * * @param Swift_Transport_SmtpAgent $agent to read/write */ public function afterEhlo(Swift_Transport_SmtpAgent $agent); /** * Get params which are appended to MAIL FROM:<>. * * @return string[] */ public function getMailParams(); /** * Get params which are appended to RCPT TO:<>. * * @return string[] */ public function getRcptParams(); /** * Runs when a command is due to be sent. * * @param Swift_Transport_SmtpAgent $agent to read/write * @param string $command to send * @param int[] $codes expected in response * @param string[] $failedRecipients to collect failures * @param bool $stop to be set true by-reference if the command is now sent */ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false); /** * Returns +1, -1 or 0 according to the rules for usort(). * * This method is called to ensure extensions can be execute in an appropriate order. * * @param string $esmtpKeyword to compare with * * @return int */ public function getPriorityOver($esmtpKeyword); /** * Returns an array of method names which are exposed to the Esmtp class. * * @return string[] */ public function exposeMixinMethods(); /** * Tells this handler to clear any buffers and reset its state. */ public function resetState(); } swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php 0000777 00000011513 14710744267 0020573 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * SendmailTransport for sending mail through a Sendmail/Postfix (etc..) binary. * * Supported modes are -bs and -t, with any additional flags desired. * It is advised to use -bs mode since error reporting with -t mode is not * possible. * * @author Chris Corbyn */ class Swift_Transport_SendmailTransport extends Swift_Transport_AbstractSmtpTransport { /** * Connection buffer parameters. * * @var array */ private $params = [ 'timeout' => 30, 'blocking' => 1, 'command' => '/usr/sbin/sendmail -bs', 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS, ]; /** * Create a new SendmailTransport with $buf for I/O. * * @param string $localDomain */ public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) { parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder); } /** * Start the standalone SMTP session if running in -bs mode. */ public function start() { if (false !== strpos($this->getCommand(), ' -bs')) { parent::start(); } } /** * Set the command to invoke. * * If using -t mode you are strongly advised to include -oi or -i in the flags. * For example: /usr/sbin/sendmail -oi -t * Swift will append a -f<sender> flag if one is not present. * * The recommended mode is "-bs" since it is interactive and failure notifications * are hence possible. * * @param string $command * * @return $this */ public function setCommand($command) { $this->params['command'] = $command; return $this; } /** * Get the sendmail command which will be invoked. * * @return string */ public function getCommand() { return $this->params['command']; } /** * Send the given Message. * * Recipient/sender data will be retrieved from the Message API. * * The return value is the number of recipients who were accepted for delivery. * NOTE: If using 'sendmail -t' you will not be aware of any failures until * they bounce (i.e. send() will always return 100% success). * * @param string[] $failedRecipients An array of failures by-reference * * @return int */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { $failedRecipients = (array) $failedRecipients; $command = $this->getCommand(); $buffer = $this->getBuffer(); $count = 0; if (false !== strpos($command, ' -t')) { if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); if ($evt->bubbleCancelled()) { return 0; } } if (false === strpos($command, ' -f')) { $command .= ' -f'.escapeshellarg($this->getReversePath($message) ?? ''); } $buffer->initialize(array_merge($this->params, ['command' => $command])); if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { $buffer->setWriteTranslations(["\r\n" => "\n", "\n." => "\n.."]); } else { $buffer->setWriteTranslations(["\r\n" => "\n"]); } $count = \count((array) $message->getTo()) + \count((array) $message->getCc()) + \count((array) $message->getBcc()) ; $message->toByteStream($buffer); $buffer->flushBuffers(); $buffer->setWriteTranslations([]); $buffer->terminate(); if ($evt) { $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); $evt->setFailedRecipients($failedRecipients); $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); } $message->generateId(); } elseif (false !== strpos($command, ' -bs')) { $count = parent::send($message, $failedRecipients); } else { $this->throwException(new Swift_TransportException( 'Unsupported sendmail command flags ['.$command.']. '. 'Must be one of "-bs" or "-t" but can include additional flags.' )); } return $count; } /** Get the params to initialize the buffer */ protected function getBufferParams() { return $this->params; } } swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php 0000777 00000027445 14710744267 0020142 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Sends Messages over SMTP with ESMTP support. * * @author Chris Corbyn */ class Swift_Transport_EsmtpTransport extends Swift_Transport_AbstractSmtpTransport implements Swift_Transport_SmtpAgent { /** * ESMTP extension handlers. * * @var Swift_Transport_EsmtpHandler[] */ private $handlers = []; /** * ESMTP capabilities. * * @var string[] */ private $capabilities = []; /** * Connection buffer parameters. * * @var array */ private $params = [ 'protocol' => 'tcp', 'host' => 'localhost', 'port' => 25, 'timeout' => 30, 'blocking' => 1, 'tls' => false, 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, 'stream_context_options' => [], ]; /** * Creates a new EsmtpTransport using the given I/O buffer. * * @param Swift_Transport_EsmtpHandler[] $extensionHandlers * @param string $localDomain */ public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) { parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder); $this->setExtensionHandlers($extensionHandlers); } /** * Set the host to connect to. * * Literal IPv6 addresses should be wrapped in square brackets. * * @param string $host * * @return $this */ public function setHost($host) { $this->params['host'] = $host; return $this; } /** * Get the host to connect to. * * @return string */ public function getHost() { return $this->params['host']; } /** * Set the port to connect to. * * @param int $port * * @return $this */ public function setPort($port) { $this->params['port'] = (int) $port; return $this; } /** * Get the port to connect to. * * @return int */ public function getPort() { return $this->params['port']; } /** * Set the connection timeout. * * @param int $timeout seconds * * @return $this */ public function setTimeout($timeout) { $this->params['timeout'] = (int) $timeout; $this->buffer->setParam('timeout', (int) $timeout); return $this; } /** * Get the connection timeout. * * @return int */ public function getTimeout() { return $this->params['timeout']; } /** * Set the encryption type (tls or ssl). * * @param string $encryption * * @return $this */ public function setEncryption($encryption) { $encryption = strtolower($encryption ?? ''); if ('tls' == $encryption) { $this->params['protocol'] = 'tcp'; $this->params['tls'] = true; } else { $this->params['protocol'] = $encryption; $this->params['tls'] = false; } return $this; } /** * Get the encryption type. * * @return string */ public function getEncryption() { return $this->params['tls'] ? 'tls' : $this->params['protocol']; } /** * Sets the stream context options. * * @param array $options * * @return $this */ public function setStreamOptions($options) { $this->params['stream_context_options'] = $options; return $this; } /** * Returns the stream context options. * * @return array */ public function getStreamOptions() { return $this->params['stream_context_options']; } /** * Sets the source IP. * * IPv6 addresses should be wrapped in square brackets. * * @param string $source * * @return $this */ public function setSourceIp($source) { $this->params['sourceIp'] = $source; return $this; } /** * Returns the IP used to connect to the destination. * * @return string */ public function getSourceIp() { return $this->params['sourceIp'] ?? null; } /** * Sets whether SMTP pipelining is enabled. * * By default, support is auto-detected using the PIPELINING SMTP extension. * Use this function to override that in the unlikely event of compatibility * issues. * * @param bool $enabled * * @return $this */ public function setPipelining($enabled) { $this->pipelining = $enabled; return $this; } /** * Returns whether SMTP pipelining is enabled. * * @return bool|null a boolean if pipelining is explicitly enabled or disabled, * or null if support is auto-detected */ public function getPipelining() { return $this->pipelining; } /** * Set ESMTP extension handlers. * * @param Swift_Transport_EsmtpHandler[] $handlers * * @return $this */ public function setExtensionHandlers(array $handlers) { $assoc = []; foreach ($handlers as $handler) { $assoc[$handler->getHandledKeyword()] = $handler; } uasort($assoc, function ($a, $b) { return $a->getPriorityOver($b->getHandledKeyword()); }); $this->handlers = $assoc; $this->setHandlerParams(); return $this; } /** * Get ESMTP extension handlers. * * @return Swift_Transport_EsmtpHandler[] */ public function getExtensionHandlers() { return array_values($this->handlers); } /** * Run a command against the buffer, expecting the given response codes. * * If no response codes are given, the response will not be validated. * If codes are given, an exception will be thrown on an invalid response. * * @param string $command * @param int[] $codes * @param string[] $failures An array of failures by-reference * @param bool $pipeline Do not wait for response * @param string $address the address, if command is RCPT TO * * @return string|null The server response, or null if pipelining is enabled */ public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null) { $failures = (array) $failures; $stopSignal = false; $response = null; foreach ($this->getActiveHandlers() as $handler) { $response = $handler->onCommand( $this, $command, $codes, $failures, $stopSignal ); if ($stopSignal) { return $response; } } return parent::executeCommand($command, $codes, $failures, $pipeline, $address); } /** Mixin handling method for ESMTP handlers */ public function __call($method, $args) { foreach ($this->handlers as $handler) { if (\in_array(strtolower($method), array_map('strtolower', (array) $handler->exposeMixinMethods()) )) { $return = \call_user_func_array([$handler, $method], $args); // Allow fluid method calls if (null === $return && 'set' == substr($method, 0, 3)) { return $this; } else { return $return; } } } trigger_error('Call to undefined method '.$method, E_USER_ERROR); } /** Get the params to initialize the buffer */ protected function getBufferParams() { return $this->params; } /** Overridden to perform EHLO instead */ protected function doHeloCommand() { try { $response = $this->executeCommand( sprintf("EHLO %s\r\n", $this->domain), [250] ); } catch (Swift_TransportException $e) { return parent::doHeloCommand(); } if ($this->params['tls']) { try { $this->executeCommand("STARTTLS\r\n", [220]); if (!$this->buffer->startTLS()) { throw new Swift_TransportException('Unable to connect with TLS encryption'); } try { $response = $this->executeCommand( sprintf("EHLO %s\r\n", $this->domain), [250] ); } catch (Swift_TransportException $e) { return parent::doHeloCommand(); } } catch (Swift_TransportException $e) { $this->throwException($e); } } $this->capabilities = $this->getCapabilities($response); if (!isset($this->pipelining)) { $this->pipelining = isset($this->capabilities['PIPELINING']); } $this->setHandlerParams(); foreach ($this->getActiveHandlers() as $handler) { $handler->afterEhlo($this); } } /** Overridden to add Extension support */ protected function doMailFromCommand($address) { $address = $this->addressEncoder->encodeString($address); $handlers = $this->getActiveHandlers(); $params = []; foreach ($handlers as $handler) { $params = array_merge($params, (array) $handler->getMailParams()); } $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; $this->executeCommand( sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), [250], $failures, true ); } /** Overridden to add Extension support */ protected function doRcptToCommand($address) { $address = $this->addressEncoder->encodeString($address); $handlers = $this->getActiveHandlers(); $params = []; foreach ($handlers as $handler) { $params = array_merge($params, (array) $handler->getRcptParams()); } $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; $this->executeCommand( sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), [250, 251, 252], $failures, true, $address ); } /** Determine ESMTP capabilities by function group */ private function getCapabilities($ehloResponse) { $capabilities = []; $ehloResponse = trim($ehloResponse ?? ''); $lines = explode("\r\n", $ehloResponse); array_shift($lines); foreach ($lines as $line) { if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { $keyword = strtoupper($matches[1]); $paramStr = strtoupper(ltrim($matches[2], ' =')); $params = !empty($paramStr) ? explode(' ', $paramStr) : []; $capabilities[$keyword] = $params; } } return $capabilities; } /** Set parameters which are used by each extension handler */ private function setHandlerParams() { foreach ($this->handlers as $keyword => $handler) { if (\array_key_exists($keyword, $this->capabilities)) { $handler->setKeywordParams($this->capabilities[$keyword]); } } } /** Get ESMTP handlers which are currently ok to use */ private function getActiveHandlers() { $handlers = []; foreach ($this->handlers as $keyword => $handler) { if (\array_key_exists($keyword, $this->capabilities)) { $handlers[] = $handler; } } return $handlers; } } swiftmailer/lib/classes/Swift/Transport/LoadBalancedTransport.php 0000777 00000011033 14710744267 0021325 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Redundantly and rotationally uses several Transports when sending. * * @author Chris Corbyn */ class Swift_Transport_LoadBalancedTransport implements Swift_Transport { /** * Transports which are deemed useless. * * @var Swift_Transport[] */ private $deadTransports = []; /** * The Transports which are used in rotation. * * @var Swift_Transport[] */ protected $transports = []; /** * The Transport used in the last successful send operation. * * @var Swift_Transport */ protected $lastUsedTransport = null; // needed as __construct is called from elsewhere explicitly public function __construct() { } /** * Set $transports to delegate to. * * @param Swift_Transport[] $transports */ public function setTransports(array $transports) { $this->transports = $transports; $this->deadTransports = []; } /** * Get $transports to delegate to. * * @return Swift_Transport[] */ public function getTransports() { return array_merge($this->transports, $this->deadTransports); } /** * Get the Transport used in the last successful send operation. * * @return Swift_Transport */ public function getLastUsedTransport() { return $this->lastUsedTransport; } /** * Test if this Transport mechanism has started. * * @return bool */ public function isStarted() { return \count($this->transports) > 0; } /** * Start this Transport mechanism. */ public function start() { $this->transports = array_merge($this->transports, $this->deadTransports); } /** * Stop this Transport mechanism. */ public function stop() { foreach ($this->transports as $transport) { $transport->stop(); } } /** * {@inheritdoc} */ public function ping() { foreach ($this->transports as $transport) { if (!$transport->ping()) { $this->killCurrentTransport(); } } return \count($this->transports) > 0; } /** * Send the given Message. * * Recipient/sender data will be retrieved from the Message API. * The return value is the number of recipients who were accepted for delivery. * * @param string[] $failedRecipients An array of failures by-reference * * @return int */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { $maxTransports = \count($this->transports); $sent = 0; $this->lastUsedTransport = null; for ($i = 0; $i < $maxTransports && $transport = $this->getNextTransport(); ++$i) { try { if (!$transport->isStarted()) { $transport->start(); } if ($sent = $transport->send($message, $failedRecipients)) { $this->lastUsedTransport = $transport; break; } } catch (Swift_TransportException $e) { $this->killCurrentTransport(); } } if (0 == \count($this->transports)) { throw new Swift_TransportException('All Transports in LoadBalancedTransport failed, or no Transports available'); } return $sent; } /** * Register a plugin. */ public function registerPlugin(Swift_Events_EventListener $plugin) { foreach ($this->transports as $transport) { $transport->registerPlugin($plugin); } } /** * Rotates the transport list around and returns the first instance. * * @return Swift_Transport */ protected function getNextTransport() { if ($next = array_shift($this->transports)) { $this->transports[] = $next; } return $next; } /** * Tag the currently used (top of stack) transport as dead/useless. */ protected function killCurrentTransport() { if ($transport = array_pop($this->transports)) { try { $transport->stop(); } catch (Exception $e) { } $this->deadTransports[] = $transport; } } } swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php 0000777 00000014202 14710744267 0020407 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An ESMTP handler for AUTH support (RFC 5248). * * @author Chris Corbyn */ class Swift_Transport_Esmtp_AuthHandler implements Swift_Transport_EsmtpHandler { /** * Authenticators available to process the request. * * @var Swift_Transport_Esmtp_Authenticator[] */ private $authenticators = []; /** * The username for authentication. * * @var string */ private $username; /** * The password for authentication. * * @var string */ private $password; /** * The auth mode for authentication. * * @var string */ private $auth_mode; /** * The ESMTP AUTH parameters available. * * @var string[] */ private $esmtpParams = []; /** * Create a new AuthHandler with $authenticators for support. * * @param Swift_Transport_Esmtp_Authenticator[] $authenticators */ public function __construct(array $authenticators) { $this->setAuthenticators($authenticators); } /** * Set the Authenticators which can process a login request. * * @param Swift_Transport_Esmtp_Authenticator[] $authenticators */ public function setAuthenticators(array $authenticators) { $this->authenticators = $authenticators; } /** * Get the Authenticators which can process a login request. * * @return Swift_Transport_Esmtp_Authenticator[] */ public function getAuthenticators() { return $this->authenticators; } /** * Set the username to authenticate with. * * @param string $username */ public function setUsername($username) { $this->username = $username; } /** * Get the username to authenticate with. * * @return string */ public function getUsername() { return $this->username; } /** * Set the password to authenticate with. * * @param string $password */ public function setPassword($password) { $this->password = $password; } /** * Get the password to authenticate with. * * @return string */ public function getPassword() { return $this->password; } /** * Set the auth mode to use to authenticate. * * @param string $mode */ public function setAuthMode($mode) { $this->auth_mode = $mode; } /** * Get the auth mode to use to authenticate. * * @return string */ public function getAuthMode() { return $this->auth_mode; } /** * Get the name of the ESMTP extension this handles. * * @return string */ public function getHandledKeyword() { return 'AUTH'; } /** * Set the parameters which the EHLO greeting indicated. * * @param string[] $parameters */ public function setKeywordParams(array $parameters) { $this->esmtpParams = $parameters; } /** * Runs immediately after a EHLO has been issued. * * @param Swift_Transport_SmtpAgent $agent to read/write */ public function afterEhlo(Swift_Transport_SmtpAgent $agent) { if ($this->username) { $count = 0; $errors = []; foreach ($this->getAuthenticatorsForAgent() as $authenticator) { if (\in_array(strtolower($authenticator->getAuthKeyword() ?? ''), array_map('strtolower', $this->esmtpParams))) { ++$count; try { if ($authenticator->authenticate($agent, $this->username, $this->password)) { return; } } catch (Swift_TransportException $e) { // keep the error message, but tries the other authenticators $errors[] = [$authenticator->getAuthKeyword(), $e->getMessage()]; } } } $message = 'Failed to authenticate on SMTP server with username "'.$this->username.'" using '.$count.' possible authenticators.'; foreach ($errors as $error) { $message .= ' Authenticator '.$error[0].' returned '.$error[1].'.'; } throw new Swift_TransportException($message); } } /** * Not used. */ public function getMailParams() { return []; } /** * Not used. */ public function getRcptParams() { return []; } /** * Not used. */ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false) { } /** * Returns +1, -1 or 0 according to the rules for usort(). * * This method is called to ensure extensions can be execute in an appropriate order. * * @param string $esmtpKeyword to compare with * * @return int */ public function getPriorityOver($esmtpKeyword) { return 0; } /** * Returns an array of method names which are exposed to the Esmtp class. * * @return string[] */ public function exposeMixinMethods() { return ['setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode']; } /** * Not used. */ public function resetState() { } /** * Returns the authenticator list for the given agent. * * @return array */ protected function getAuthenticatorsForAgent() { if (!$mode = strtolower($this->auth_mode ?? '')) { return $this->authenticators; } foreach ($this->authenticators as $authenticator) { if (strtolower($authenticator->getAuthKeyword() ?? '') == $mode) { return [$authenticator]; } } throw new Swift_TransportException('Auth mode '.$mode.' is invalid'); } } swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php 0000777 00000001715 14710744267 0021027 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An Authentication mechanism. * * @author Chris Corbyn */ interface Swift_Transport_Esmtp_Authenticator { /** * Get the name of the AUTH mechanism this Authenticator handles. * * @return string */ public function getAuthKeyword(); /** * Try to authenticate the user with $username and $password. * * @param string $username * @param string $password * * @return bool true if authentication worked (returning false is deprecated, throw a Swift_TransportException instead) * * @throws Swift_TransportException Allows the message to bubble up when authentication was not successful */ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password); } swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php 0000777 00000003201 14710744267 0023073 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles XOAUTH2 authentication. * * Example: * <code> * $transport = (new Swift_SmtpTransport('smtp.gmail.com', 587, 'tls')) * ->setAuthMode('XOAUTH2') * ->setUsername('YOUR_EMAIL_ADDRESS') * ->setPassword('YOUR_ACCESS_TOKEN'); * </code> * * @author xu.li<AthenaLightenedMyPath@gmail.com> * * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol */ class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator { /** * Get the name of the AUTH mechanism this Authenticator handles. * * @return string */ public function getAuthKeyword() { return 'XOAUTH2'; } /** * {@inheritdoc} */ public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token) { try { $param = $this->constructXOAuth2Params($email, $token); $agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", [235]); return true; } catch (Swift_TransportException $e) { $agent->executeCommand("RSET\r\n", [250]); throw $e; } } /** * Construct the auth parameter. * * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism */ protected function constructXOAuth2Params($email, $token) { return base64_encode("user=$email\1auth=Bearer $token\1\1"); } } swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php 0000777 00000002157 14710744267 0022722 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles LOGIN authentication. * * @author Chris Corbyn */ class Swift_Transport_Esmtp_Auth_LoginAuthenticator implements Swift_Transport_Esmtp_Authenticator { /** * Get the name of the AUTH mechanism this Authenticator handles. * * @return string */ public function getAuthKeyword() { return 'LOGIN'; } /** * {@inheritdoc} */ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) { try { $agent->executeCommand("AUTH LOGIN\r\n", [334]); $agent->executeCommand(sprintf("%s\r\n", base64_encode($username ?? '')), [334]); $agent->executeCommand(sprintf("%s\r\n", base64_encode($password ?? '')), [235]); return true; } catch (Swift_TransportException $e) { $agent->executeCommand("RSET\r\n", [250]); throw $e; } } } swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php 0000777 00000051747 14710744267 0022435 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * This authentication is for Exchange servers. We support version 1 & 2. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles NTLM authentication. * * @author Ward Peeters <ward@coding-tech.com> */ class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator { const NTLMSIG = "NTLMSSP\x00"; const DESCONST = 'KGS!@#$%'; /** * Get the name of the AUTH mechanism this Authenticator handles. * * @return string */ public function getAuthKeyword() { return 'NTLM'; } /** * {@inheritdoc} * * @throws \LogicException */ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) { if (!\function_exists('openssl_encrypt')) { throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); } if (!\function_exists('bcmul')) { throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.'); } try { // execute AUTH command and filter out the code at the beginning // AUTH NTLM xxxx $response = base64_decode(substr(trim($this->sendMessage1($agent) ?? ''), 4)); // extra parameters for our unit cases $timestamp = \func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000')); $client = \func_num_args() > 4 ? func_get_arg(4) : random_bytes(8); // Message 3 response $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent); return true; } catch (Swift_TransportException $e) { $agent->executeCommand("RSET\r\n", [250]); throw $e; } } protected function si2bin($si, $bits = 32) { $bin = null; if ($si >= -2 ** ($bits - 1) && ($si <= 2 ** ($bits - 1))) { // positive or zero if ($si >= 0) { $bin = base_convert($si, 10, 2); // pad to $bits bit $bin_length = \strlen($bin); if ($bin_length < $bits) { $bin = str_repeat('0', $bits - $bin_length).$bin; } } else { // negative $si = -$si - 2 ** $bits; $bin = base_convert($si, 10, 2); $bin_length = \strlen($bin); if ($bin_length > $bits) { $bin = str_repeat('1', $bits - $bin_length).$bin; } } } return $bin; } /** * Send our auth message and returns the response. * * @return string SMTP Response */ protected function sendMessage1(Swift_Transport_SmtpAgent $agent) { $message = $this->createMessage1(); return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), [334]); } /** * Fetch all details of our response (message 2). * * @param string $response * * @return array our response parsed */ protected function parseMessage2($response) { $responseHex = bin2hex($response); $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2; $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2; $challenge = hex2bin(substr($responseHex, 48, 16)); $context = hex2bin(substr($responseHex, 64, 16)); $targetInfoH = hex2bin(substr($responseHex, 80, 16)); $targetName = hex2bin(substr($responseHex, $offset, $length)); $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2; $targetInfoBlock = substr($responseHex, $offset); list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock); return [ $challenge, $context, $targetInfoH, $targetName, $domainName, $serverName, $DNSDomainName, $DNSServerName, hex2bin($targetInfoBlock), $terminatorByte, ]; } /** * Read the blob information in from message2. * * @return array */ protected function readSubBlock($block) { // remove terminatorByte cause it's always the same $block = substr($block, 0, -8); $length = \strlen($block); $offset = 0; $data = []; while ($offset < $length) { $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256; $offset += 8; $data[] = hex2bin(substr($block, $offset, $blockLength * 2)); $offset += $blockLength * 2; } if (3 == \count($data)) { $data[] = $data[2]; $data[2] = ''; } $data[] = $this->createByte('00'); return $data; } /** * Send our final message with all our data. * * @param string $response Message 1 response (message 2) * @param string $username * @param string $password * @param string $timestamp * @param string $client * @param bool $v2 Use version2 of the protocol * * @return string */ protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true) { list($domain, $username) = $this->getDomainAndUsername($username); //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response); if (!$v2) { // LMv1 $lmResponse = $this->createLMPassword($password, $challenge); // NTLMv1 $ntlmResponse = $this->createNTLMPassword($password, $challenge); } else { // LMv2 $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client); // NTLMv2 $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client); } $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse); return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), [235]); } /** * Create our message 1. * * @return string */ protected function createMessage1() { return self::NTLMSIG .$this->createByte('01') // Message 1 .$this->createByte('0702'); // Flags } /** * Create our message 3. * * @param string $domain * @param string $username * @param string $workstation * @param string $lmResponse * @param string $ntlmResponse * * @return string */ protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse) { // Create security buffers $domainSec = $this->createSecurityBuffer($domain, 64); $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec)); $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2); $userInfo = $this->readSecurityBuffer(bin2hex($userSec)); $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2); $workInfo = $this->readSecurityBuffer(bin2hex($workSec)); $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true); $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec)); $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true); return self::NTLMSIG .$this->createByte('03') // TYPE 3 message .$lmSec // LM response header .$ntlmSec // NTLM response header .$domainSec // Domain header .$userSec // User header .$workSec // Workstation header .$this->createByte('000000009a', 8) // session key header (empty) .$this->createByte('01020000') // FLAGS .$this->convertTo16bit($domain) // domain name .$this->convertTo16bit($username) // username .$this->convertTo16bit($workstation) // workstation .$lmResponse .$ntlmResponse; } /** * @param string $timestamp Epoch timestamp in microseconds * @param string $client Random bytes * @param string $targetInfo * * @return string */ protected function createBlob($timestamp, $client, $targetInfo) { return $this->createByte('0101') .$this->createByte('00') .$timestamp .$client .$this->createByte('00') .$targetInfo .$this->createByte('00'); } /** * Get domain and username from our username. * * @example DOMAIN\username * * @param string $name * * @return array */ protected function getDomainAndUsername($name) { if (false !== strpos($name, '\\')) { return explode('\\', $name); } if (false !== strpos($name, '@')) { list($user, $domain) = explode('@', $name); return [$domain, $user]; } // no domain passed return ['', $name]; } /** * Create LMv1 response. * * @param string $password * @param string $challenge * * @return string */ protected function createLMPassword($password, $challenge) { // FIRST PART $password = $this->createByte(strtoupper($password), 14, false); list($key1, $key2) = str_split($password, 7); $desKey1 = $this->createDesKey($key1); $desKey2 = $this->createDesKey($key2); $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false); // SECOND PART list($key1, $key2, $key3) = str_split($constantDecrypt, 7); $desKey1 = $this->createDesKey($key1); $desKey2 = $this->createDesKey($key2); $desKey3 = $this->createDesKey($key3); return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); } /** * Create NTLMv1 response. * * @param string $password * @param string $challenge * * @return string */ protected function createNTLMPassword($password, $challenge) { // FIRST PART $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false); list($key1, $key2, $key3) = str_split($ntlmHash, 7); $desKey1 = $this->createDesKey($key1); $desKey2 = $this->createDesKey($key2); $desKey3 = $this->createDesKey($key3); return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); } /** * Convert a normal timestamp to a tenth of a microtime epoch time. * * @param string $time * * @return string */ protected function getCorrectTimestamp($time) { // Get our timestamp (tricky!) $time = number_format($time, 0, '.', ''); // save microtime to string $time = bcadd($time, '11644473600000', 0); // add epoch time $time = bcmul($time, 10000, 0); // tenths of a microsecond. $binary = $this->si2bin($time, 64); // create 64 bit binary string $timestamp = ''; for ($i = 0; $i < 8; ++$i) { $timestamp .= \chr(bindec(substr($binary, -(($i + 1) * 8), 8))); } return $timestamp; } /** * Create LMv2 response. * * @param string $password * @param string $username * @param string $domain * @param string $challenge NTLM Challenge * @param string $client Random string * * @return string */ protected function createLMv2Password($password, $username, $domain, $challenge, $client) { $lmPass = '00'; // by default 00 // if $password > 15 than we can't use this method if (\strlen($password) <= 15) { $ntlmHash = $this->md4Encrypt($password); $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client); } return $this->createByte($lmPass, 24); } /** * Create NTLMv2 response. * * @param string $password * @param string $username * @param string $domain * @param string $challenge Hex values * @param string $targetInfo Hex values * @param string $timestamp * @param string $client Random bytes * * @return string * * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse */ protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client) { $ntlmHash = $this->md4Encrypt($password); $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); // create blob $blob = $this->createBlob($timestamp, $client, $targetInfo); $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob); return $ntlmv2Response.$blob; } protected function createDesKey($key) { $material = [bin2hex($key[0])]; $len = \strlen($key); for ($i = 1; $i < $len; ++$i) { list($high, $low) = str_split(bin2hex($key[$i])); $v = $this->castToByte(\ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i)); $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte } $material[] = str_pad(substr(dechex($this->castToByte(\ord($key[6]) << 1)), -2), 2, '0'); // odd parity foreach ($material as $k => $v) { $b = $this->castToByte(hexdec($v)); $needsParity = 0 == (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5) ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2) ^ $this->uRShift($b, 1)) & 0x01); list($high, $low) = str_split($v); if ($needsParity) { $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1); } else { $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe); } } return hex2bin(implode('', $material)); } /** HELPER FUNCTIONS */ /** * Create our security buffer depending on length and offset. * * @param string $value Value we want to put in * @param int $offset start of value * @param bool $is16 Do we 16bit string or not? * * @return string */ protected function createSecurityBuffer($value, $offset, $is16 = false) { $length = \strlen(bin2hex($value)); $length = $is16 ? $length / 2 : $length; $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2); return $length.$length.$this->createByte(dechex($offset), 4); } /** * Read our security buffer to fetch length and offset of our value. * * @param string $value Securitybuffer in hex * * @return array array with length and offset */ protected function readSecurityBuffer($value) { $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2; $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2; return [$length, $offset]; } /** * Cast to byte java equivalent to (byte). * * @param int $v * * @return int */ protected function castToByte($v) { return (($v + 128) % 256) - 128; } /** * Java unsigned right bitwise * $a >>> $b. * * @param int $a * @param int $b * * @return int */ protected function uRShift($a, $b) { if (0 == $b) { return $a; } return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1)); } /** * Right padding with 0 to certain length. * * @param string $input * @param int $bytes Length of bytes * @param bool $isHex Did we provided hex value * * @return string */ protected function createByte($input, $bytes = 4, $isHex = true) { if ($isHex) { $byte = hex2bin(str_pad($input, $bytes * 2, '00')); } else { $byte = str_pad($input, $bytes, "\x00"); } return $byte; } /** ENCRYPTION ALGORITHMS */ /** * DES Encryption. * * @param string $value An 8-byte string * @param string $key * * @return string */ protected function desEncrypt($value, $key) { return substr(openssl_encrypt($value, 'DES-ECB', $key, \OPENSSL_RAW_DATA), 0, 8); } /** * MD5 Encryption. * * @param string $key Encryption key * @param string $msg Message to encrypt * * @return string */ protected function md5Encrypt($key, $msg) { $blocksize = 64; if (\strlen($key) > $blocksize) { $key = pack('H*', md5($key)); } $key = str_pad($key, $blocksize, "\0"); $ipadk = $key ^ str_repeat("\x36", $blocksize); $opadk = $key ^ str_repeat("\x5c", $blocksize); return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg)))); } /** * MD4 Encryption. * * @param string $input * * @return string * * @see https://secure.php.net/manual/en/ref.hash.php */ protected function md4Encrypt($input) { $input = $this->convertTo16bit($input); return \function_exists('hash') ? hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input); } /** * Convert UTF-8 to UTF-16. * * @param string $input * * @return string */ protected function convertTo16bit($input) { return iconv('UTF-8', 'UTF-16LE', $input); } /** * @param string $message */ protected function debug($message) { $message = bin2hex($message); $messageId = substr($message, 16, 8); echo substr($message, 0, 16)." NTLMSSP Signature<br />\n"; echo $messageId." Type Indicator<br />\n"; if ('02000000' == $messageId) { $map = [ 'Challenge', 'Context', 'Target Information Security Buffer', 'Target Name Data', 'NetBIOS Domain Name', 'NetBIOS Server Name', 'DNS Domain Name', 'DNS Server Name', 'BLOB', 'Target Information Terminator', ]; $data = $this->parseMessage2(hex2bin($message)); foreach ($map as $key => $value) { echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."<br />\n"; } } elseif ('03000000' == $messageId) { $i = 0; $data[$i++] = substr($message, 24, 16); list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]); $data[$i++] = substr($message, 40, 16); list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]); $data[$i++] = substr($message, 56, 16); list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]); $data[$i++] = substr($message, 72, 16); list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]); $data[$i++] = substr($message, 88, 16); list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]); $data[$i++] = substr($message, 104, 16); $data[$i++] = substr($message, 120, 8); $data[$i++] = substr($message, $targetOffset, $targetLength); $data[$i++] = substr($message, $userOffset, $userLength); $data[$i++] = substr($message, $workOffset, $workLength); $data[$i++] = substr($message, $lmOffset, $lmLength); $data[$i] = substr($message, $ntmlOffset, $ntmlLength); $map = [ 'LM Response Security Buffer', 'NTLM Response Security Buffer', 'Target Name Security Buffer', 'User Name Security Buffer', 'Workstation Name Security Buffer', 'Session Key Security Buffer', 'Flags', 'Target Name Data', 'User Name Data', 'Workstation Name Data', 'LM Response Data', 'NTLM Response Data', ]; foreach ($map as $key => $value) { echo $data[$key].' - '.hex2bin($data[$key]).' ||| '.$value."<br />\n"; } } echo '<br /><br />'; } } swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php 0000777 00000003614 14710744267 0023101 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles CRAM-MD5 authentication. * * @author Chris Corbyn */ class Swift_Transport_Esmtp_Auth_CramMd5Authenticator implements Swift_Transport_Esmtp_Authenticator { /** * Get the name of the AUTH mechanism this Authenticator handles. * * @return string */ public function getAuthKeyword() { return 'CRAM-MD5'; } /** * {@inheritdoc} */ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) { try { $challenge = $agent->executeCommand("AUTH CRAM-MD5\r\n", [334]); $challenge = base64_decode(substr($challenge, 4)); $message = base64_encode( $username.' '.$this->getResponse($password, $challenge) ); $agent->executeCommand(sprintf("%s\r\n", $message), [235]); return true; } catch (Swift_TransportException $e) { $agent->executeCommand("RSET\r\n", [250]); throw $e; } } /** * Generate a CRAM-MD5 response from a server challenge. * * @param string $secret * @param string $challenge * * @return string */ private function getResponse($secret, $challenge) { if (\strlen($secret) > 64) { $secret = pack('H32', md5($secret)); } if (\strlen($secret) < 64) { $secret = str_pad($secret, 64, \chr(0)); } $k_ipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64); $k_opad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64); $inner = pack('H32', md5($k_ipad.$challenge)); $digest = md5($k_opad.$inner); return $digest; } } swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php 0000777 00000002036 14710744267 0022711 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles PLAIN authentication. * * @author Chris Corbyn */ class Swift_Transport_Esmtp_Auth_PlainAuthenticator implements Swift_Transport_Esmtp_Authenticator { /** * Get the name of the AUTH mechanism this Authenticator handles. * * @return string */ public function getAuthKeyword() { return 'PLAIN'; } /** * {@inheritdoc} */ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) { try { $message = base64_encode($username.\chr(0).$username.\chr(0).$password); $agent->executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), [235]); return true; } catch (Swift_TransportException $e) { $agent->executeCommand("RSET\r\n", [250]); throw $e; } } } swiftmailer/lib/classes/Swift/Transport/Esmtp/EightBitMimeHandler.php 0000777 00000004641 14710744267 0022023 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2018 Christian Schmidt * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An ESMTP handler for 8BITMIME support (RFC 6152). * * 8BITMIME is required when sending 8-bit content to over SMTP, e.g. when using * Swift_Mime_ContentEncoder_PlainContentEncoder in "8bit" mode. * * 8BITMIME mode is enabled unconditionally, even when sending ASCII-only * messages, so it should only be used with an outbound SMTP server that will * convert the message to 7-bit MIME if the next hop does not support 8BITMIME. * * @author Christian Schmidt */ class Swift_Transport_Esmtp_EightBitMimeHandler implements Swift_Transport_EsmtpHandler { protected $encoding; /** * @param string $encoding The parameter so send with the MAIL FROM command; * either "8BITMIME" or "7BIT" */ public function __construct(string $encoding = '8BITMIME') { $this->encoding = $encoding; } /** * Get the name of the ESMTP extension this handles. * * @return string */ public function getHandledKeyword() { return '8BITMIME'; } /** * Not used. */ public function setKeywordParams(array $parameters) { } /** * Not used. */ public function afterEhlo(Swift_Transport_SmtpAgent $agent) { } /** * Get params which are appended to MAIL FROM:<>. * * @return string[] */ public function getMailParams() { return ['BODY='.$this->encoding]; } /** * Not used. */ public function getRcptParams() { return []; } /** * Not used. */ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false) { } /** * Returns +1, -1 or 0 according to the rules for usort(). * * This method is called to ensure extensions can be execute in an appropriate order. * * @param string $esmtpKeyword to compare with * * @return int */ public function getPriorityOver($esmtpKeyword) { return 0; } /** * Not used. */ public function exposeMixinMethods() { return []; } /** * Not used. */ public function resetState() { } } swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php 0000777 00000004342 14710744267 0021204 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2018 Christian Schmidt * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An ESMTP handler for SMTPUTF8 support (RFC 6531). * * SMTPUTF8 is required when sending to email addresses containing non-ASCII * characters in local-part (the substring before @). This handler should be * used together with Swift_AddressEncoder_Utf8AddressEncoder. * * SMTPUTF8 mode is enabled unconditionally, even when sending to ASCII-only * addresses, so it should only be used with an outbound SMTP server that will * deliver ASCII-only messages even if the next hop does not support SMTPUTF8. * * @author Christian Schmidt */ class Swift_Transport_Esmtp_SmtpUtf8Handler implements Swift_Transport_EsmtpHandler { public function __construct() { } /** * Get the name of the ESMTP extension this handles. * * @return string */ public function getHandledKeyword() { return 'SMTPUTF8'; } /** * Not used. */ public function setKeywordParams(array $parameters) { } /** * Not used. */ public function afterEhlo(Swift_Transport_SmtpAgent $agent) { } /** * Get params which are appended to MAIL FROM:<>. * * @return string[] */ public function getMailParams() { return ['SMTPUTF8']; } /** * Not used. */ public function getRcptParams() { return []; } /** * Not used. */ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false) { } /** * Returns +1, -1 or 0 according to the rules for usort(). * * This method is called to ensure extensions can be execute in an appropriate order. * * @param string $esmtpKeyword to compare with * * @return int */ public function getPriorityOver($esmtpKeyword) { return 0; } /** * Not used. */ public function exposeMixinMethods() { return []; } /** * Not used. */ public function resetState() { } } swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php 0000777 00000037257 14710744267 0021463 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Sends Messages over SMTP. * * @author Chris Corbyn */ abstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport { /** Input-Output buffer for sending/receiving SMTP commands and responses */ protected $buffer; /** Connection status */ protected $started = false; /** The domain name to use in HELO command */ protected $domain = '[127.0.0.1]'; /** The event dispatching layer */ protected $eventDispatcher; protected $addressEncoder; /** Whether the PIPELINING SMTP extension is enabled (RFC 2920) */ protected $pipelining = null; /** The pipelined commands waiting for response */ protected $pipeline = []; /** Source Ip */ protected $sourceIp; /** Return an array of params for the Buffer */ abstract protected function getBufferParams(); /** * Creates a new EsmtpTransport using the given I/O buffer. * * @param string $localDomain */ public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) { $this->buffer = $buf; $this->eventDispatcher = $dispatcher; $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); $this->setLocalDomain($localDomain); } /** * Set the name of the local domain which Swift will identify itself as. * * This should be a fully-qualified domain name and should be truly the domain * you're using. * * If your server does not have a domain name, use the IP address. This will * automatically be wrapped in square brackets as described in RFC 5321, * section 4.1.3. * * @param string $domain * * @return $this */ public function setLocalDomain($domain) { if ('[' !== substr($domain, 0, 1)) { if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $domain = '['.$domain.']'; } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $domain = '[IPv6:'.$domain.']'; } } $this->domain = $domain; return $this; } /** * Get the name of the domain Swift will identify as. * * If an IP address was specified, this will be returned wrapped in square * brackets as described in RFC 5321, section 4.1.3. * * @return string */ public function getLocalDomain() { return $this->domain; } /** * Sets the source IP. * * @param string $source */ public function setSourceIp($source) { $this->sourceIp = $source; } /** * Returns the IP used to connect to the destination. * * @return string */ public function getSourceIp() { return $this->sourceIp; } public function setAddressEncoder(Swift_AddressEncoder $addressEncoder) { $this->addressEncoder = $addressEncoder; } public function getAddressEncoder() { return $this->addressEncoder; } /** * Start the SMTP connection. */ public function start() { if (!$this->started) { if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) { $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted'); if ($evt->bubbleCancelled()) { return; } } try { $this->buffer->initialize($this->getBufferParams()); } catch (Swift_TransportException $e) { $this->throwException($e); } $this->readGreeting(); $this->doHeloCommand(); if ($evt) { $this->eventDispatcher->dispatchEvent($evt, 'transportStarted'); } $this->started = true; } } /** * Test if an SMTP connection has been established. * * @return bool */ public function isStarted() { return $this->started; } /** * Send the given Message. * * Recipient/sender data will be retrieved from the Message API. * The return value is the number of recipients who were accepted for delivery. * * @param string[] $failedRecipients An array of failures by-reference * * @return int */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { if (!$this->isStarted()) { $this->start(); } $sent = 0; $failedRecipients = (array) $failedRecipients; if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); if ($evt->bubbleCancelled()) { return 0; } } if (!$reversePath = $this->getReversePath($message)) { $this->throwException(new Swift_TransportException('Cannot send message without a sender address')); } $to = (array) $message->getTo(); $cc = (array) $message->getCc(); $bcc = (array) $message->getBcc(); $tos = array_merge($to, $cc, $bcc); $message->setBcc([]); try { $sent += $this->sendTo($message, $reversePath, $tos, $failedRecipients); } finally { $message->setBcc($bcc); } if ($evt) { if ($sent == \count($to) + \count($cc) + \count($bcc)) { $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); } elseif ($sent > 0) { $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE); } else { $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); } $evt->setFailedRecipients($failedRecipients); $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); } $message->generateId(); //Make sure a new Message ID is used return $sent; } /** * Stop the SMTP connection. */ public function stop() { if ($this->started) { if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) { $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped'); if ($evt->bubbleCancelled()) { return; } } try { $this->executeCommand("QUIT\r\n", [221]); } catch (Swift_TransportException $e) { } try { $this->buffer->terminate(); if ($evt) { $this->eventDispatcher->dispatchEvent($evt, 'transportStopped'); } } catch (Swift_TransportException $e) { $this->throwException($e); } } $this->started = false; } /** * {@inheritdoc} */ public function ping() { try { if (!$this->isStarted()) { $this->start(); } $this->executeCommand("NOOP\r\n", [250]); } catch (Swift_TransportException $e) { try { $this->stop(); } catch (Swift_TransportException $e) { } return false; } return true; } /** * Register a plugin. */ public function registerPlugin(Swift_Events_EventListener $plugin) { $this->eventDispatcher->bindEventListener($plugin); } /** * Reset the current mail transaction. */ public function reset() { $this->executeCommand("RSET\r\n", [250], $failures, true); } /** * Get the IoBuffer where read/writes are occurring. * * @return Swift_Transport_IoBuffer */ public function getBuffer() { return $this->buffer; } /** * Run a command against the buffer, expecting the given response codes. * * If no response codes are given, the response will not be validated. * If codes are given, an exception will be thrown on an invalid response. * If the command is RCPT TO, and the pipeline is non-empty, no exception * will be thrown; instead the failing address is added to $failures. * * @param string $command * @param int[] $codes * @param string[] $failures An array of failures by-reference * @param bool $pipeline Do not wait for response * @param string $address the address, if command is RCPT TO * * @return string|null The server response, or null if pipelining is enabled */ public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null) { $failures = (array) $failures; $seq = $this->buffer->write($command); if ($evt = $this->eventDispatcher->createCommandEvent($this, $command, $codes)) { $this->eventDispatcher->dispatchEvent($evt, 'commandSent'); } $this->pipeline[] = [$command, $seq, $codes, $address]; if ($pipeline && $this->pipelining) { return null; } $response = null; while ($this->pipeline) { list($command, $seq, $codes, $address) = array_shift($this->pipeline); $response = $this->getFullResponse($seq); try { $this->assertResponseCode($response, $codes); } catch (Swift_TransportException $e) { if ($this->pipeline && $address) { $failures[] = $address; } else { $this->throwException($e); } } } return $response; } /** Read the opening SMTP greeting */ protected function readGreeting() { $this->assertResponseCode($this->getFullResponse(0), [220]); } /** Send the HELO welcome */ protected function doHeloCommand() { $this->executeCommand( sprintf("HELO %s\r\n", $this->domain), [250] ); } /** Send the MAIL FROM command */ protected function doMailFromCommand($address) { $address = $this->addressEncoder->encodeString($address); $this->executeCommand( sprintf("MAIL FROM:<%s>\r\n", $address), [250], $failures, true ); } /** Send the RCPT TO command */ protected function doRcptToCommand($address) { $address = $this->addressEncoder->encodeString($address); $this->executeCommand( sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252], $failures, true, $address ); } /** Send the DATA command */ protected function doDataCommand(&$failedRecipients) { $this->executeCommand("DATA\r\n", [354], $failedRecipients); } /** Stream the contents of the message over the buffer */ protected function streamMessage(Swift_Mime_SimpleMessage $message) { $this->buffer->setWriteTranslations(["\r\n." => "\r\n.."]); try { $message->toByteStream($this->buffer); $this->buffer->flushBuffers(); } catch (Swift_TransportException $e) { $this->throwException($e); } $this->buffer->setWriteTranslations([]); $this->executeCommand("\r\n.\r\n", [250]); } /** Determine the best-use reverse path for this message */ protected function getReversePath(Swift_Mime_SimpleMessage $message) { $return = $message->getReturnPath(); $sender = $message->getSender(); $from = $message->getFrom(); $path = null; if (!empty($return)) { $path = $return; } elseif (!empty($sender)) { // Don't use array_keys reset($sender); // Reset Pointer to first pos $path = key($sender); // Get key } elseif (!empty($from)) { reset($from); // Reset Pointer to first pos $path = key($from); // Get key } return $path; } /** Throw a TransportException, first sending it to any listeners */ protected function throwException(Swift_TransportException $e) { if ($evt = $this->eventDispatcher->createTransportExceptionEvent($this, $e)) { $this->eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); if (!$evt->bubbleCancelled()) { throw $e; } } else { throw $e; } } /** Throws an Exception if a response code is incorrect */ protected function assertResponseCode($response, $wanted) { if (!$response) { $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got an empty response')); } list($code) = sscanf($response, '%3d'); $valid = (empty($wanted) || \in_array($code, $wanted)); if ($evt = $this->eventDispatcher->createResponseEvent($this, $response, $valid)) { $this->eventDispatcher->dispatchEvent($evt, 'responseReceived'); } if (!$valid) { $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got code "'.$code.'", with message "'.$response.'"', $code)); } } /** Get an entire multi-line response using its sequence number */ protected function getFullResponse($seq) { $response = ''; try { do { $line = $this->buffer->readLine($seq); $response .= $line; } while (null !== $line && false !== $line && ' ' != $line[3]); } catch (Swift_TransportException $e) { $this->throwException($e); } catch (Swift_IoException $e) { $this->throwException(new Swift_TransportException($e->getMessage(), 0, $e)); } return $response; } /** Send an email to the given recipients from the given reverse path */ private function doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients) { $sent = 0; $this->doMailFromCommand($reversePath); foreach ($recipients as $forwardPath) { try { $this->doRcptToCommand($forwardPath); ++$sent; } catch (Swift_TransportException $e) { $failedRecipients[] = $forwardPath; } catch (Swift_AddressEncoderException $e) { $failedRecipients[] = $forwardPath; } } if (0 != $sent) { $sent += \count($failedRecipients); $this->doDataCommand($failedRecipients); $sent -= \count($failedRecipients); $this->streamMessage($message); } else { $this->reset(); } return $sent; } /** Send a message to the given To: recipients */ private function sendTo(Swift_Mime_SimpleMessage $message, $reversePath, array $to, array &$failedRecipients) { if (empty($to)) { return 0; } return $this->doMailTransaction($message, $reversePath, array_keys($to), $failedRecipients); } /** * Destructor. */ public function __destruct() { try { $this->stop(); } catch (Exception $e) { } } public function __sleep() { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } public function __wakeup() { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } } swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php 0000777 00000001713 14710744267 0017025 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Wraps an IoBuffer to send/receive SMTP commands/responses. * * @author Chris Corbyn */ interface Swift_Transport_SmtpAgent { /** * Get the IoBuffer where read/writes are occurring. * * @return Swift_Transport_IoBuffer */ public function getBuffer(); /** * Run a command against the buffer, expecting the given response codes. * * If no response codes are given, the response will not be validated. * If codes are given, an exception will be thrown on an invalid response. * * @param string $command * @param int[] $codes * @param string[] $failures An array of failures by-reference */ public function executeCommand($command, $codes = [], &$failures = null); } swiftmailer/lib/classes/Swift/Transport/SpoolTransport.php 0000777 00000005007 14710744267 0020134 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Stores Messages in a queue. * * @author Fabien Potencier */ class Swift_Transport_SpoolTransport implements Swift_Transport { /** The spool instance */ private $spool; /** The event dispatcher from the plugin API */ private $eventDispatcher; /** * Constructor. */ public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) { $this->eventDispatcher = $eventDispatcher; $this->spool = $spool; } /** * Sets the spool object. * * @return $this */ public function setSpool(Swift_Spool $spool) { $this->spool = $spool; return $this; } /** * Get the spool object. * * @return Swift_Spool */ public function getSpool() { return $this->spool; } /** * Tests if this Transport mechanism has started. * * @return bool */ public function isStarted() { return true; } /** * Starts this Transport mechanism. */ public function start() { } /** * Stops this Transport mechanism. */ public function stop() { } /** * {@inheritdoc} */ public function ping() { return true; } /** * Sends the given message. * * @param string[] $failedRecipients An array of failures by-reference * * @return int The number of sent e-mail's */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) { $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); if ($evt->bubbleCancelled()) { return 0; } } $success = $this->spool->queueMessage($message); if ($evt) { $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SPOOLED : Swift_Events_SendEvent::RESULT_FAILED); $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed'); } return 1; } /** * Register a plugin. */ public function registerPlugin(Swift_Events_EventListener $plugin) { $this->eventDispatcher->bindEventListener($plugin); } } swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php 0000777 00000005303 14710744267 0020606 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Contains a list of redundant Transports so when one fails, the next is used. * * @author Chris Corbyn */ class Swift_Transport_FailoverTransport extends Swift_Transport_LoadBalancedTransport { /** * Registered transport currently used. * * @var Swift_Transport */ private $currentTransport; // needed as __construct is called from elsewhere explicitly public function __construct() { parent::__construct(); } /** * {@inheritdoc} */ public function ping() { $maxTransports = \count($this->transports); for ($i = 0; $i < $maxTransports && $transport = $this->getNextTransport(); ++$i) { if ($transport->ping()) { return true; } else { $this->killCurrentTransport(); } } return \count($this->transports) > 0; } /** * Send the given Message. * * Recipient/sender data will be retrieved from the Message API. * The return value is the number of recipients who were accepted for delivery. * * @param string[] $failedRecipients An array of failures by-reference * * @return int */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { $maxTransports = \count($this->transports); $sent = 0; $this->lastUsedTransport = null; for ($i = 0; $i < $maxTransports && $transport = $this->getNextTransport(); ++$i) { try { if (!$transport->isStarted()) { $transport->start(); } if ($sent = $transport->send($message, $failedRecipients)) { $this->lastUsedTransport = $transport; return $sent; } } catch (Swift_TransportException $e) { $this->killCurrentTransport(); } } if (0 == \count($this->transports)) { throw new Swift_TransportException('All Transports in FailoverTransport failed, or no Transports available'); } return $sent; } protected function getNextTransport() { if (!isset($this->currentTransport)) { $this->currentTransport = parent::getNextTransport(); } return $this->currentTransport; } protected function killCurrentTransport() { $this->currentTransport = null; parent::killCurrentTransport(); } } swiftmailer/lib/classes/Swift/Message.php 0000777 00000015777 14710744267 0014532 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * The Message class for building emails. * * @author Chris Corbyn */ class Swift_Message extends Swift_Mime_SimpleMessage { /** * @var Swift_Signers_HeaderSigner[] */ private $headerSigners = []; /** * @var Swift_Signers_BodySigner[] */ private $bodySigners = []; /** * @var array */ private $savedMessage = []; /** * Create a new Message. * * Details may be optionally passed into the constructor. * * @param string $subject * @param string $body * @param string $contentType * @param string $charset */ public function __construct($subject = null, $body = null, $contentType = null, $charset = null) { \call_user_func_array( [$this, 'Swift_Mime_SimpleMessage::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('mime.message') ); if (!isset($charset)) { $charset = Swift_DependencyContainer::getInstance() ->lookup('properties.charset'); } $this->setSubject($subject); $this->setBody($body); $this->setCharset($charset); if ($contentType) { $this->setContentType($contentType); } } /** * Add a MimePart to this Message. * * @param string|Swift_OutputByteStream $body * @param string $contentType * @param string $charset * * @return $this */ public function addPart($body, $contentType = null, $charset = null) { return $this->attach((new Swift_MimePart($body, $contentType, $charset))->setEncoder($this->getEncoder())); } /** * Attach a new signature handler to the message. * * @return $this */ public function attachSigner(Swift_Signer $signer) { if ($signer instanceof Swift_Signers_HeaderSigner) { $this->headerSigners[] = $signer; } elseif ($signer instanceof Swift_Signers_BodySigner) { $this->bodySigners[] = $signer; } return $this; } /** * Detach a signature handler from a message. * * @return $this */ public function detachSigner(Swift_Signer $signer) { if ($signer instanceof Swift_Signers_HeaderSigner) { foreach ($this->headerSigners as $k => $headerSigner) { if ($headerSigner === $signer) { unset($this->headerSigners[$k]); return $this; } } } elseif ($signer instanceof Swift_Signers_BodySigner) { foreach ($this->bodySigners as $k => $bodySigner) { if ($bodySigner === $signer) { unset($this->bodySigners[$k]); return $this; } } } return $this; } /** * Clear all signature handlers attached to the message. * * @return $this */ public function clearSigners() { $this->headerSigners = []; $this->bodySigners = []; return $this; } /** * Get this message as a complete string. * * @return string */ public function toString() { if (empty($this->headerSigners) && empty($this->bodySigners)) { return parent::toString(); } $this->saveMessage(); $this->doSign(); $string = parent::toString(); $this->restoreMessage(); return $string; } /** * Write this message to a {@link Swift_InputByteStream}. */ public function toByteStream(Swift_InputByteStream $is) { if (empty($this->headerSigners) && empty($this->bodySigners)) { parent::toByteStream($is); return; } $this->saveMessage(); $this->doSign(); parent::toByteStream($is); $this->restoreMessage(); } public function __wakeup() { Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message'); } /** * loops through signers and apply the signatures. */ protected function doSign() { foreach ($this->bodySigners as $signer) { $altered = $signer->getAlteredHeaders(); $this->saveHeaders($altered); $signer->signMessage($this); } foreach ($this->headerSigners as $signer) { $altered = $signer->getAlteredHeaders(); $this->saveHeaders($altered); $signer->reset(); $signer->setHeaders($this->getHeaders()); $signer->startBody(); $this->bodyToByteStream($signer); $signer->endBody(); $signer->addSignature($this->getHeaders()); } } /** * save the message before any signature is applied. */ protected function saveMessage() { $this->savedMessage = ['headers' => []]; $this->savedMessage['body'] = $this->getBody(); $this->savedMessage['children'] = $this->getChildren(); if (\count($this->savedMessage['children']) > 0 && '' != $this->getBody()) { $this->setChildren(array_merge([$this->becomeMimePart()], $this->savedMessage['children'])); $this->setBody(''); } } /** * save the original headers. */ protected function saveHeaders(array $altered) { foreach ($altered as $head) { $lc = strtolower($head ?? ''); if (!isset($this->savedMessage['headers'][$lc])) { $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head); } } } /** * Remove or restore altered headers. */ protected function restoreHeaders() { foreach ($this->savedMessage['headers'] as $name => $savedValue) { $headers = $this->getHeaders()->getAll($name); foreach ($headers as $key => $value) { if (!isset($savedValue[$key])) { $this->getHeaders()->remove($name, $key); } } } } /** * Restore message body. */ protected function restoreMessage() { $this->setBody($this->savedMessage['body']); $this->setChildren($this->savedMessage['children']); $this->restoreHeaders(); $this->savedMessage = []; } /** * Clone Message Signers. * * @see Swift_Mime_SimpleMimeEntity::__clone() */ public function __clone() { parent::__clone(); foreach ($this->bodySigners as $key => $bodySigner) { $this->bodySigners[$key] = clone $bodySigner; } foreach ($this->headerSigners as $key => $headerSigner) { $this->headerSigners[$key] = clone $headerSigner; } } } swiftmailer/lib/classes/Swift/MimePart.php 0000777 00000002220 14710744267 0014637 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A MIME part, in a multipart message. * * @author Chris Corbyn */ class Swift_MimePart extends Swift_Mime_MimePart { /** * Create a new MimePart. * * Details may be optionally passed into the constructor. * * @param string $body * @param string $contentType * @param string $charset */ public function __construct($body = null, $contentType = null, $charset = null) { \call_user_func_array( [$this, 'Swift_Mime_MimePart::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('mime.part') ); if (!isset($charset)) { $charset = Swift_DependencyContainer::getInstance() ->lookup('properties.charset'); } $this->setBody($body); $this->setCharset($charset); if ($contentType) { $this->setContentType($contentType); } } } swiftmailer/lib/classes/Swift/Signer.php 0000777 00000000555 14710744267 0014361 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Base Class of Signer Infrastructure. * * @author Xavier De Cock <xdecock@gmail.com> */ interface Swift_Signer { public function reset(); } swiftmailer/lib/classes/Swift/Spool.php 0000777 00000002330 14710744267 0014217 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Interface for spools. * * @author Fabien Potencier */ interface Swift_Spool { /** * Starts this Spool mechanism. */ public function start(); /** * Stops this Spool mechanism. */ public function stop(); /** * Tests if this Spool mechanism has started. * * @return bool */ public function isStarted(); /** * Queues a message. * * @param Swift_Mime_SimpleMessage $message The message to store * * @return bool Whether the operation has succeeded */ public function queueMessage(Swift_Mime_SimpleMessage $message); /** * Sends messages using the given transport instance. * * @param Swift_Transport $transport A transport instance * @param string[] $failedRecipients An array of failures by-reference * * @return int The number of sent emails */ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null); } swiftmailer/lib/classes/Swift/AddressEncoder/Utf8AddressEncoder.php 0000777 00000002130 14710744267 0021442 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2018 Christian Schmidt * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A UTF-8 email address encoder. * * Returns the email address verbatimly in UTF-8 as permitted by RFC 6531 and * RFC 6532. It supports addresses containing non-ASCII characters in both * local-part and domain (i.e. on both sides of @). * * This encoder must be used together with Swift_Transport_Esmtp_SmtpUtf8Handler * and requires that the outbound SMTP server supports the SMTPUTF8 extension. * * If your outbound SMTP server does not support SMTPUTF8, use * Swift_AddressEncoder_IdnAddressEncoder instead. This allows sending to email * addresses with non-ASCII characters in the domain, but not in local-part. * * @author Christian Schmidt */ class Swift_AddressEncoder_Utf8AddressEncoder implements Swift_AddressEncoder { /** * Returns the address verbatimly. */ public function encodeString(string $address): string { return $address; } } swiftmailer/lib/classes/Swift/AddressEncoder/IdnAddressEncoder.php 0000777 00000003056 14710744267 0021336 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2018 Christian Schmidt * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An IDN email address encoder. * * Encodes the domain part of an address using IDN. This is compatible will all * SMTP servers. * * This encoder does not support email addresses with non-ASCII characters in * local-part (the substring before @). To send to such addresses, use * Swift_AddressEncoder_Utf8AddressEncoder together with * Swift_Transport_Esmtp_SmtpUtf8Handler. Your outbound SMTP server must support * the SMTPUTF8 extension. * * @author Christian Schmidt */ class Swift_AddressEncoder_IdnAddressEncoder implements Swift_AddressEncoder { /** * Encodes the domain part of an address using IDN. * * @throws Swift_AddressEncoderException If local-part contains non-ASCII characters */ public function encodeString(string $address): string { $i = strrpos($address, '@'); if (false !== $i) { $local = substr($address, 0, $i); $domain = substr($address, $i + 1); if (preg_match('/[^\x00-\x7F]/', $local)) { throw new Swift_AddressEncoderException('Non-ASCII characters not supported in local-part', $address); } if (preg_match('/[^\x00-\x7F]/', $domain)) { $address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46)); } } return $address; } } swiftmailer/lib/classes/Swift/OutputByteStream.php 0000777 00000002150 14710744267 0016423 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An abstract means of reading data. * * Classes implementing this interface may use a subsystem which requires less * memory than working with large strings of data. * * @author Chris Corbyn */ interface Swift_OutputByteStream { /** * Reads $length bytes from the stream into a string and moves the pointer * through the stream by $length. * * If less bytes exist than are requested the remaining bytes are given instead. * If no bytes are remaining at all, boolean false is returned. * * @param int $length * * @throws Swift_IoException * * @return string|bool */ public function read($length); /** * Move the internal read pointer to $byteOffset in the stream. * * @param int $byteOffset * * @throws Swift_IoException * * @return bool */ public function setReadPointer($byteOffset); } swiftmailer/lib/classes/Swift/Image.php 0000777 00000002034 14710744267 0014146 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An image, embedded in a multipart message. * * @author Chris Corbyn */ class Swift_Image extends Swift_EmbeddedFile { /** * Create a new EmbeddedFile. * * Details may be optionally provided to the constructor. * * @param string|Swift_OutputByteStream $data * @param string $filename * @param string $contentType */ public function __construct($data = null, $filename = null, $contentType = null) { parent::__construct($data, $filename, $contentType); } /** * Create a new Image from a filesystem path. * * @param string $path * * @return self */ public static function fromPath($path) { return (new self())->setFile(new Swift_ByteStream_FileByteStream($path)); } } swiftmailer/lib/classes/Swift/CharacterStream.php 0000777 00000004156 14710744267 0016203 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An abstract means of reading and writing data in terms of characters as opposed * to bytes. * * Classes implementing this interface may use a subsystem which requires less * memory than working with large strings of data. * * @author Chris Corbyn */ interface Swift_CharacterStream { /** * Set the character set used in this CharacterStream. * * @param string $charset */ public function setCharacterSet($charset); /** * Set the CharacterReaderFactory for multi charset support. */ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory); /** * Overwrite this character stream using the byte sequence in the byte stream. * * @param Swift_OutputByteStream $os output stream to read from */ public function importByteStream(Swift_OutputByteStream $os); /** * Import a string a bytes into this CharacterStream, overwriting any existing * data in the stream. * * @param string $string */ public function importString($string); /** * Read $length characters from the stream and move the internal pointer * $length further into the stream. * * @param int $length * * @return string */ public function read($length); /** * Read $length characters from the stream and return a 1-dimensional array * containing there octet values. * * @param int $length * * @return int[] */ public function readBytes($length); /** * Write $chars to the end of the stream. * * @param string $chars */ public function write($chars); /** * Move the internal pointer to $charOffset in the stream. * * @param int $charOffset */ public function setPointer($charOffset); /** * Empty the stream and reset the internal pointer. */ public function flushContents(); } swiftmailer/lib/classes/Swift/StreamFilter.php 0000777 00000001320 14710744267 0015522 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Processes bytes as they pass through a stream and performs filtering. * * @author Chris Corbyn */ interface Swift_StreamFilter { /** * Based on the buffer given, this returns true if more buffering is needed. * * @param mixed $buffer * * @return bool */ public function shouldBuffer($buffer); /** * Filters $buffer and returns the changes. * * @param mixed $buffer * * @return mixed */ public function filter($buffer); } swiftmailer/lib/classes/Swift/AddressEncoderException.php 0000777 00000001321 14710744267 0017666 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2018 Christian Schmidt * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * AddressEncoderException when the specified email address is in a format that * cannot be encoded by a given address encoder. * * @author Christian Schmidt */ class Swift_AddressEncoderException extends Swift_RfcComplianceException { protected $address; public function __construct(string $message, string $address) { parent::__construct($message); $this->address = $address; } public function getAddress(): string { return $this->address; } } swiftmailer/lib/classes/Swift/SpoolTransport.php 0000777 00000001414 14710744267 0016136 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Stores Messages in a queue. * * @author Fabien Potencier */ class Swift_SpoolTransport extends Swift_Transport_SpoolTransport { /** * Create a new SpoolTransport. */ public function __construct(Swift_Spool $spool) { $arguments = Swift_DependencyContainer::getInstance() ->createDependenciesFor('transport.spool'); $arguments[] = $spool; \call_user_func_array( [$this, 'Swift_Transport_SpoolTransport::__construct'], $arguments ); } } swiftmailer/lib/classes/Swift/TransportException.php 0000777 00000001236 14710744267 0017002 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * TransportException thrown when an error occurs in the Transport subsystem. * * @author Chris Corbyn */ class Swift_TransportException extends Swift_IoException { /** * Create a new TransportException with $message. * * @param string $message * @param int $code */ public function __construct($message, $code = 0, Exception $previous = null) { parent::__construct($message, $code, $previous); } } swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php 0000777 00000040051 14710744267 0016552 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * The default email message class. * * @author Chris Corbyn */ class Swift_Mime_SimpleMessage extends Swift_Mime_MimePart { const PRIORITY_HIGHEST = 1; const PRIORITY_HIGH = 2; const PRIORITY_NORMAL = 3; const PRIORITY_LOW = 4; const PRIORITY_LOWEST = 5; /** * Create a new SimpleMessage with $headers, $encoder and $cache. * * @param string $charset */ public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator, $charset = null) { parent::__construct($headers, $encoder, $cache, $idGenerator, $charset); $this->getHeaders()->defineOrdering([ 'Return-Path', 'Received', 'DKIM-Signature', 'DomainKey-Signature', 'Sender', 'Message-ID', 'Date', 'Subject', 'From', 'Reply-To', 'To', 'Cc', 'Bcc', 'MIME-Version', 'Content-Type', 'Content-Transfer-Encoding', ]); $this->getHeaders()->setAlwaysDisplayed(['Date', 'Message-ID', 'From']); $this->getHeaders()->addTextHeader('MIME-Version', '1.0'); $this->setDate(new DateTimeImmutable()); $this->setId($this->getId()); $this->getHeaders()->addMailboxHeader('From'); } /** * Always returns {@link LEVEL_TOP} for a message instance. * * @return int */ public function getNestingLevel() { return self::LEVEL_TOP; } /** * Set the subject of this message. * * @param string $subject * * @return $this */ public function setSubject($subject) { if (!$this->setHeaderFieldModel('Subject', $subject)) { $this->getHeaders()->addTextHeader('Subject', $subject); } return $this; } /** * Get the subject of this message. * * @return string */ public function getSubject() { return $this->getHeaderFieldModel('Subject'); } /** * Set the date at which this message was created. * * @return $this */ public function setDate(DateTimeInterface $dateTime) { if (!$this->setHeaderFieldModel('Date', $dateTime)) { $this->getHeaders()->addDateHeader('Date', $dateTime); } return $this; } /** * Get the date at which this message was created. * * @return DateTimeInterface */ public function getDate() { return $this->getHeaderFieldModel('Date'); } /** * Set the return-path (the bounce address) of this message. * * @param string $address * * @return $this */ public function setReturnPath($address) { if (!$this->setHeaderFieldModel('Return-Path', $address)) { $this->getHeaders()->addPathHeader('Return-Path', $address); } return $this; } /** * Get the return-path (bounce address) of this message. * * @return string */ public function getReturnPath() { return $this->getHeaderFieldModel('Return-Path'); } /** * Set the sender of this message. * * This does not override the From field, but it has a higher significance. * * @param string $address * @param string $name optional * * @return $this */ public function setSender($address, $name = null) { if (!\is_array($address) && isset($name)) { $address = [$address => $name]; } if (!$this->setHeaderFieldModel('Sender', (array) $address)) { $this->getHeaders()->addMailboxHeader('Sender', (array) $address); } return $this; } /** * Get the sender of this message. * * @return string */ public function getSender() { return $this->getHeaderFieldModel('Sender'); } /** * Add a From: address to this message. * * If $name is passed this name will be associated with the address. * * @param string $address * @param string $name optional * * @return $this */ public function addFrom($address, $name = null) { $current = $this->getFrom(); $current[$address] = $name; return $this->setFrom($current); } /** * Set the from address of this message. * * You may pass an array of addresses if this message is from multiple people. * * If $name is passed and the first parameter is a string, this name will be * associated with the address. * * @param string|array $addresses * @param string $name optional * * @return $this */ public function setFrom($addresses, $name = null) { if (!\is_array($addresses) && isset($name)) { $addresses = [$addresses => $name]; } if (!$this->setHeaderFieldModel('From', (array) $addresses)) { $this->getHeaders()->addMailboxHeader('From', (array) $addresses); } return $this; } /** * Get the from address of this message. * * @return mixed */ public function getFrom() { return $this->getHeaderFieldModel('From'); } /** * Add a Reply-To: address to this message. * * If $name is passed this name will be associated with the address. * * @param string $address * @param string $name optional * * @return $this */ public function addReplyTo($address, $name = null) { $current = $this->getReplyTo(); $current[$address] = $name; return $this->setReplyTo($current); } /** * Set the reply-to address of this message. * * You may pass an array of addresses if replies will go to multiple people. * * If $name is passed and the first parameter is a string, this name will be * associated with the address. * * @param mixed $addresses * @param string $name optional * * @return $this */ public function setReplyTo($addresses, $name = null) { if (!\is_array($addresses) && isset($name)) { $addresses = [$addresses => $name]; } if (!$this->setHeaderFieldModel('Reply-To', (array) $addresses)) { $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses); } return $this; } /** * Get the reply-to address of this message. * * @return string */ public function getReplyTo() { return $this->getHeaderFieldModel('Reply-To'); } /** * Add a To: address to this message. * * If $name is passed this name will be associated with the address. * * @param string $address * @param string $name optional * * @return $this */ public function addTo($address, $name = null) { $current = $this->getTo(); $current[$address] = $name; return $this->setTo($current); } /** * Set the to addresses of this message. * * If multiple recipients will receive the message an array should be used. * Example: array('receiver@domain.org', 'other@domain.org' => 'A name') * * If $name is passed and the first parameter is a string, this name will be * associated with the address. * * @param mixed $addresses * @param string $name optional * * @return $this */ public function setTo($addresses, $name = null) { if (!\is_array($addresses) && isset($name)) { $addresses = [$addresses => $name]; } if (!$this->setHeaderFieldModel('To', (array) $addresses)) { $this->getHeaders()->addMailboxHeader('To', (array) $addresses); } return $this; } /** * Get the To addresses of this message. * * @return array */ public function getTo() { return $this->getHeaderFieldModel('To'); } /** * Add a Cc: address to this message. * * If $name is passed this name will be associated with the address. * * @param string $address * @param string $name optional * * @return $this */ public function addCc($address, $name = null) { $current = $this->getCc(); $current[$address] = $name; return $this->setCc($current); } /** * Set the Cc addresses of this message. * * If $name is passed and the first parameter is a string, this name will be * associated with the address. * * @param mixed $addresses * @param string $name optional * * @return $this */ public function setCc($addresses, $name = null) { if (!\is_array($addresses) && isset($name)) { $addresses = [$addresses => $name]; } if (!$this->setHeaderFieldModel('Cc', (array) $addresses)) { $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses); } return $this; } /** * Get the Cc address of this message. * * @return array */ public function getCc() { return $this->getHeaderFieldModel('Cc'); } /** * Add a Bcc: address to this message. * * If $name is passed this name will be associated with the address. * * @param string $address * @param string $name optional * * @return $this */ public function addBcc($address, $name = null) { $current = $this->getBcc(); $current[$address] = $name; return $this->setBcc($current); } /** * Set the Bcc addresses of this message. * * If $name is passed and the first parameter is a string, this name will be * associated with the address. * * @param mixed $addresses * @param string $name optional * * @return $this */ public function setBcc($addresses, $name = null) { if (!\is_array($addresses) && isset($name)) { $addresses = [$addresses => $name]; } if (!$this->setHeaderFieldModel('Bcc', (array) $addresses)) { $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses); } return $this; } /** * Get the Bcc addresses of this message. * * @return array */ public function getBcc() { return $this->getHeaderFieldModel('Bcc'); } /** * Set the priority of this message. * * The value is an integer where 1 is the highest priority and 5 is the lowest. * * @param int $priority * * @return $this */ public function setPriority($priority) { $priorityMap = [ self::PRIORITY_HIGHEST => 'Highest', self::PRIORITY_HIGH => 'High', self::PRIORITY_NORMAL => 'Normal', self::PRIORITY_LOW => 'Low', self::PRIORITY_LOWEST => 'Lowest', ]; $pMapKeys = array_keys($priorityMap); if ($priority > max($pMapKeys)) { $priority = max($pMapKeys); } elseif ($priority < min($pMapKeys)) { $priority = min($pMapKeys); } if (!$this->setHeaderFieldModel('X-Priority', sprintf('%d (%s)', $priority, $priorityMap[$priority]))) { $this->getHeaders()->addTextHeader('X-Priority', sprintf('%d (%s)', $priority, $priorityMap[$priority])); } return $this; } /** * Get the priority of this message. * * The returned value is an integer where 1 is the highest priority and 5 * is the lowest. * * @return int */ public function getPriority() { list($priority) = sscanf($this->getHeaderFieldModel('X-Priority'), '%[1-5]' ); return $priority ?? 3; } /** * Ask for a delivery receipt from the recipient to be sent to $addresses. * * @param array $addresses * * @return $this */ public function setReadReceiptTo($addresses) { if (!$this->setHeaderFieldModel('Disposition-Notification-To', $addresses)) { $this->getHeaders() ->addMailboxHeader('Disposition-Notification-To', $addresses); } return $this; } /** * Get the addresses to which a read-receipt will be sent. * * @return string */ public function getReadReceiptTo() { return $this->getHeaderFieldModel('Disposition-Notification-To'); } /** * Attach a {@link Swift_Mime_SimpleMimeEntity} such as an Attachment or MimePart. * * @return $this */ public function attach(Swift_Mime_SimpleMimeEntity $entity) { $this->setChildren(array_merge($this->getChildren(), [$entity])); return $this; } /** * Remove an already attached entity. * * @return $this */ public function detach(Swift_Mime_SimpleMimeEntity $entity) { $newChildren = []; foreach ($this->getChildren() as $child) { if ($entity !== $child) { $newChildren[] = $child; } } $this->setChildren($newChildren); return $this; } /** * Attach a {@link Swift_Mime_SimpleMimeEntity} and return it's CID source. * * This method should be used when embedding images or other data in a message. * * @return string */ public function embed(Swift_Mime_SimpleMimeEntity $entity) { $this->attach($entity); return 'cid:'.$entity->getId(); } /** * Get this message as a complete string. * * @return string */ public function toString() { if (\count($children = $this->getChildren()) > 0 && '' != $this->getBody()) { $this->setChildren(array_merge([$this->becomeMimePart()], $children)); $string = parent::toString(); $this->setChildren($children); } else { $string = parent::toString(); } return $string; } /** * Returns a string representation of this object. * * @see toString() * * @return string */ public function __toString() { return $this->toString(); } /** * Write this message to a {@link Swift_InputByteStream}. */ public function toByteStream(Swift_InputByteStream $is) { if (\count($children = $this->getChildren()) > 0 && '' != $this->getBody()) { $this->setChildren(array_merge([$this->becomeMimePart()], $children)); parent::toByteStream($is); $this->setChildren($children); } else { parent::toByteStream($is); } } /** @see Swift_Mime_SimpleMimeEntity::getIdField() */ protected function getIdField() { return 'Message-ID'; } /** Turn the body of this message into a child of itself if needed */ protected function becomeMimePart() { $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(), $this->getCache(), $this->getIdGenerator(), $this->userCharset ); $part->setContentType($this->userContentType); $part->setBody($this->getBody()); $part->setFormat($this->userFormat); $part->setDelSp($this->userDelSp); $part->setNestingLevel($this->getTopNestingLevel()); return $part; } /** Get the highest nesting level nested inside this message */ private function getTopNestingLevel() { $highestLevel = $this->getNestingLevel(); foreach ($this->getChildren() as $child) { $childLevel = $child->getNestingLevel(); if ($highestLevel < $childLevel) { $highestLevel = $childLevel; } } return $highestLevel; } } swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php 0000777 00000004261 14710744267 0021212 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A Simple MIME Header. * * @author Chris Corbyn */ class Swift_Mime_Headers_UnstructuredHeader extends Swift_Mime_Headers_AbstractHeader { /** * The value of this Header. * * @var string */ private $value; /** * Creates a new SimpleHeader with $name. * * @param string $name */ public function __construct($name, Swift_Mime_HeaderEncoder $encoder) { $this->setFieldName($name); $this->setEncoder($encoder); } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_TEXT; } /** * Set the model for the field body. * * This method takes a string for the field value. * * @param string $model */ public function setFieldBodyModel($model) { $this->setValue($model); } /** * Get the model for the field body. * * This method returns a string. * * @return string */ public function getFieldBodyModel() { return $this->getValue(); } /** * Get the (unencoded) value of this header. * * @return string */ public function getValue() { return $this->value; } /** * Set the (unencoded) value of this header. * * @param string $value */ public function setValue($value) { $this->clearCachedValueIf($this->value != $value); $this->value = $value; } /** * Get the value of this header prepared for rendering. * * @return string */ public function getFieldBody() { if (!$this->getCachedValue()) { $this->setCachedValue( $this->encodeWords($this, $this->value) ); } return $this->getCachedValue(); } } swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php 0000777 00000007325 14710744267 0017403 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\RFCValidation; /** * A Path Header in Swift Mailer, such a Return-Path. * * @author Chris Corbyn */ class Swift_Mime_Headers_PathHeader extends Swift_Mime_Headers_AbstractHeader { /** * The address in this Header (if specified). * * @var string */ private $address; /** * The strict EmailValidator. * * @var EmailValidator */ private $emailValidator; private $addressEncoder; /** * Creates a new PathHeader with the given $name. * * @param string $name */ public function __construct($name, EmailValidator $emailValidator, Swift_AddressEncoder $addressEncoder = null) { $this->setFieldName($name); $this->emailValidator = $emailValidator; $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_PATH; } /** * Set the model for the field body. * This method takes a string for an address. * * @param string $model * * @throws Swift_RfcComplianceException */ public function setFieldBodyModel($model) { $this->setAddress($model); } /** * Get the model for the field body. * This method returns a string email address. * * @return mixed */ public function getFieldBodyModel() { return $this->getAddress(); } /** * Set the Address which should appear in this Header. * * @param string $address * * @throws Swift_RfcComplianceException */ public function setAddress($address) { if (null === $address) { $this->address = null; } elseif ('' == $address) { $this->address = ''; } else { $this->assertValidAddress($address); $this->address = $address; } $this->setCachedValue(null); } /** * Get the address which is used in this Header (if any). * * Null is returned if no address is set. * * @return string */ public function getAddress() { return $this->address; } /** * Get the string value of the body in this Header. * * This is not necessarily RFC 2822 compliant since folding white space will * not be added at this stage (see {@link toString()} for that). * * @see toString() * * @return string */ public function getFieldBody() { if (!$this->getCachedValue()) { if (isset($this->address)) { $address = $this->addressEncoder->encodeString($this->address); $this->setCachedValue('<'.$address.'>'); } } return $this->getCachedValue(); } /** * Throws an Exception if the address passed does not comply with RFC 2822. * * @param string $address * * @throws Swift_RfcComplianceException If address is invalid */ private function assertValidAddress($address) { if (!$this->emailValidator->isValid($address, new RFCValidation())) { throw new Swift_RfcComplianceException('Address set in PathHeader does not comply with addr-spec of RFC 2822.'); } } } swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php 0000777 00000015616 14710744267 0021305 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An abstract base MIME Header. * * @author Chris Corbyn */ class Swift_Mime_Headers_ParameterizedHeader extends Swift_Mime_Headers_UnstructuredHeader { /** * RFC 2231's definition of a token. * * @var string */ const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)'; /** * The Encoder used to encode the parameters. * * @var Swift_Encoder */ private $paramEncoder; /** * The parameters as an associative array. * * @var string[] */ private $params = []; /** * Creates a new ParameterizedHeader with $name. * * @param string $name */ public function __construct($name, Swift_Mime_HeaderEncoder $encoder, Swift_Encoder $paramEncoder = null) { parent::__construct($name, $encoder); $this->paramEncoder = $paramEncoder; } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_PARAMETERIZED; } /** * Set the character set used in this Header. * * @param string $charset */ public function setCharset($charset) { parent::setCharset($charset); if (isset($this->paramEncoder)) { $this->paramEncoder->charsetChanged($charset); } } /** * Set the value of $parameter. * * @param string $parameter * @param string $value */ public function setParameter($parameter, $value) { $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); } /** * Get the value of $parameter. * * @param string $parameter * * @return string */ public function getParameter($parameter) { $params = $this->getParameters(); return $params[$parameter] ?? null; } /** * Set an associative array of parameter names mapped to values. * * @param string[] $parameters */ public function setParameters(array $parameters) { $this->clearCachedValueIf($this->params != $parameters); $this->params = $parameters; } /** * Returns an associative array of parameter names mapped to values. * * @return string[] */ public function getParameters() { return $this->params; } /** * Get the value of this header prepared for rendering. * * @return string */ public function getFieldBody() //TODO: Check caching here { $body = parent::getFieldBody(); foreach ($this->params as $name => $value) { if (null !== $value) { // Add the parameter $body .= '; '.$this->createParameter($name, $value); } } return $body; } /** * Generate a list of all tokens in the final header. * * This doesn't need to be overridden in theory, but it is for implementation * reasons to prevent potential breakage of attributes. * * @param string $string The string to tokenize * * @return array An array of tokens as strings */ protected function toTokens($string = null) { $tokens = parent::toTokens(parent::getFieldBody()); // Try creating any parameters foreach ($this->params as $name => $value) { if (null !== $value) { // Add the semi-colon separator $tokens[\count($tokens) - 1] .= ';'; $tokens = array_merge($tokens, $this->generateTokenLines( ' '.$this->createParameter($name, $value) )); } } return $tokens; } /** * Render a RFC 2047 compliant header parameter from the $name and $value. * * @param string $name * @param string $value * * @return string */ private function createParameter($name, $value) { $origValue = $value; $encoded = false; // Allow room for parameter name, indices, "=" and DQUOTEs $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; $firstLineOffset = 0; // If it's not already a valid parameter value... if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { // TODO: text, or something else?? // ... and it's not ascii if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { $encoded = true; // Allow space for the indices, charset and language $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; $firstLineOffset = \strlen( $this->getCharset()."'".$this->getLanguage()."'" ); } } // Encode if we need to if ($encoded || \strlen($value) > $maxValueLength) { if (isset($this->paramEncoder)) { $value = $this->paramEncoder->encodeString( $origValue, $firstLineOffset, $maxValueLength, $this->getCharset() ); } else { // We have to go against RFC 2183/2231 in some areas for interoperability $value = $this->getTokenAsEncodedWord($origValue); $encoded = false; } } $valueLines = isset($this->paramEncoder) ? explode("\r\n", $value) : [$value]; // Need to add indices if (\count($valueLines) > 1) { $paramLines = []; foreach ($valueLines as $i => $line) { $paramLines[] = $name.'*'.$i. $this->getEndOfParameterValue($line, true, 0 == $i); } return implode(";\r\n ", $paramLines); } else { return $name.$this->getEndOfParameterValue( $valueLines[0], $encoded, true ); } } /** * Returns the parameter value from the "=" and beyond. * * @param string $value to append * @param bool $encoded * @param bool $firstLine * * @return string */ private function getEndOfParameterValue($value, $encoded = false, $firstLine = false) { if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { $value = '"'.$value.'"'; } $prepend = '='; if ($encoded) { $prepend = '*='; if ($firstLine) { $prepend = '*='.$this->getCharset()."'".$this->getLanguage(). "'"; } } return $prepend.$value; } } swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php 0000777 00000005202 14710744267 0017354 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A Date MIME Header for Swift Mailer. * * @author Chris Corbyn */ class Swift_Mime_Headers_DateHeader extends Swift_Mime_Headers_AbstractHeader { /** * Date-time value of this Header. * * @var DateTimeImmutable */ private $dateTime; /** * Creates a new DateHeader with $name. * * @param string $name of Header */ public function __construct($name) { $this->setFieldName($name); } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_DATE; } /** * Set the model for the field body. * * @param DateTimeInterface $model */ public function setFieldBodyModel($model) { $this->setDateTime($model); } /** * Get the model for the field body. * * @return DateTimeImmutable */ public function getFieldBodyModel() { return $this->getDateTime(); } /** * Get the date-time representing the Date in this Header. * * @return DateTimeImmutable */ public function getDateTime() { return $this->dateTime; } /** * Set the date-time of the Date in this Header. * * If a DateTime instance is provided, it is converted to DateTimeImmutable. */ public function setDateTime(DateTimeInterface $dateTime) { $this->clearCachedValueIf($this->getCachedValue() != $dateTime->format(DateTime::RFC2822)); if ($dateTime instanceof DateTime) { $immutable = new DateTimeImmutable('@'.$dateTime->getTimestamp()); $dateTime = $immutable->setTimezone($dateTime->getTimezone()); } $this->dateTime = $dateTime; } /** * Get the string value of the body in this Header. * * This is not necessarily RFC 2822 compliant since folding white space will * not be added at this stage (see {@link toString()} for that). * * @see toString() * * @return string */ public function getFieldBody() { if (!$this->getCachedValue()) { if (isset($this->dateTime)) { $this->setCachedValue($this->dateTime->format(DateTime::RFC2822)); } } return $this->getCachedValue(); } } swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php 0000777 00000005030 14710744267 0020044 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An OpenDKIM Specific Header using only raw header datas without encoding. * * @author De Cock Xavier <xdecock@gmail.com> * * @deprecated since SwiftMailer 6.1.0; use Swift_Signers_DKIMSigner instead. */ class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header { /** * The value of this Header. * * @var string */ private $value; /** * The name of this Header. * * @var string */ private $fieldName; /** * @param string $name */ public function __construct($name) { $this->fieldName = $name; } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_TEXT; } /** * Set the model for the field body. * * This method takes a string for the field value. * * @param string $model */ public function setFieldBodyModel($model) { $this->setValue($model); } /** * Get the model for the field body. * * This method returns a string. * * @return string */ public function getFieldBodyModel() { return $this->getValue(); } /** * Get the (unencoded) value of this header. * * @return string */ public function getValue() { return $this->value; } /** * Set the (unencoded) value of this header. * * @param string $value */ public function setValue($value) { $this->value = $value; } /** * Get the value of this header prepared for rendering. * * @return string */ public function getFieldBody() { return $this->value; } /** * Get this Header rendered as a RFC 2822 compliant string. * * @return string */ public function toString() { return $this->fieldName.': '.$this->value."\r\n"; } /** * Set the Header FieldName. * * @see Swift_Mime_Header::getFieldName() */ public function getFieldName() { return $this->fieldName; } /** * Ignored. */ public function setCharset($charset) { } } swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php 0000777 00000022451 14710744267 0020077 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\RFCValidation; /** * A Mailbox Address MIME Header for something like From or Sender. * * @author Chris Corbyn */ class Swift_Mime_Headers_MailboxHeader extends Swift_Mime_Headers_AbstractHeader { /** * The mailboxes used in this Header. * * @var string[] */ private $mailboxes = []; /** * The strict EmailValidator. * * @var EmailValidator */ private $emailValidator; private $addressEncoder; /** * Creates a new MailboxHeader with $name. * * @param string $name of Header */ public function __construct($name, Swift_Mime_HeaderEncoder $encoder, EmailValidator $emailValidator, Swift_AddressEncoder $addressEncoder = null) { $this->setFieldName($name); $this->setEncoder($encoder); $this->emailValidator = $emailValidator; $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_MAILBOX; } /** * Set the model for the field body. * * This method takes a string, or an array of addresses. * * @param mixed $model * * @throws Swift_RfcComplianceException */ public function setFieldBodyModel($model) { $this->setNameAddresses($model); } /** * Get the model for the field body. * * This method returns an associative array like {@link getNameAddresses()} * * @throws Swift_RfcComplianceException * * @return array */ public function getFieldBodyModel() { return $this->getNameAddresses(); } /** * Set a list of mailboxes to be shown in this Header. * * The mailboxes can be a simple array of addresses, or an array of * key=>value pairs where (email => personalName). * Example: * <code> * <?php * //Sets two mailboxes in the Header, one with a personal name * $header->setNameAddresses(array( * 'chris@swiftmailer.org' => 'Chris Corbyn', * 'mark@swiftmailer.org' //No associated personal name * )); * ?> * </code> * * @see __construct() * @see setAddresses() * @see setValue() * * @param string|string[] $mailboxes * * @throws Swift_RfcComplianceException */ public function setNameAddresses($mailboxes) { $this->mailboxes = $this->normalizeMailboxes((array) $mailboxes); $this->setCachedValue(null); //Clear any cached value } /** * Get the full mailbox list of this Header as an array of valid RFC 2822 strings. * * Example: * <code> * <?php * $header = new Swift_Mime_Headers_MailboxHeader('From', * array('chris@swiftmailer.org' => 'Chris Corbyn', * 'mark@swiftmailer.org' => 'Mark Corbyn') * ); * print_r($header->getNameAddressStrings()); * // array ( * // 0 => Chris Corbyn <chris@swiftmailer.org>, * // 1 => Mark Corbyn <mark@swiftmailer.org> * // ) * ?> * </code> * * @see getNameAddresses() * @see toString() * * @throws Swift_RfcComplianceException * * @return string[] */ public function getNameAddressStrings() { return $this->createNameAddressStrings($this->getNameAddresses()); } /** * Get all mailboxes in this Header as key=>value pairs. * * The key is the address and the value is the name (or null if none set). * Example: * <code> * <?php * $header = new Swift_Mime_Headers_MailboxHeader('From', * array('chris@swiftmailer.org' => 'Chris Corbyn', * 'mark@swiftmailer.org' => 'Mark Corbyn') * ); * print_r($header->getNameAddresses()); * // array ( * // chris@swiftmailer.org => Chris Corbyn, * // mark@swiftmailer.org => Mark Corbyn * // ) * ?> * </code> * * @see getAddresses() * @see getNameAddressStrings() * * @return string[] */ public function getNameAddresses() { return $this->mailboxes; } /** * Makes this Header represent a list of plain email addresses with no names. * * Example: * <code> * <?php * //Sets three email addresses as the Header data * $header->setAddresses( * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld') * ); * ?> * </code> * * @see setNameAddresses() * @see setValue() * * @param string[] $addresses * * @throws Swift_RfcComplianceException */ public function setAddresses($addresses) { $this->setNameAddresses(array_values((array) $addresses)); } /** * Get all email addresses in this Header. * * @see getNameAddresses() * * @return string[] */ public function getAddresses() { return array_keys($this->mailboxes); } /** * Remove one or more addresses from this Header. * * @param string|string[] $addresses */ public function removeAddresses($addresses) { $this->setCachedValue(null); foreach ((array) $addresses as $address) { unset($this->mailboxes[$address]); } } /** * Get the string value of the body in this Header. * * This is not necessarily RFC 2822 compliant since folding white space will * not be added at this stage (see {@link toString()} for that). * * @see toString() * * @throws Swift_RfcComplianceException * * @return string */ public function getFieldBody() { // Compute the string value of the header only if needed if (null === $this->getCachedValue()) { $this->setCachedValue($this->createMailboxListString($this->mailboxes)); } return $this->getCachedValue(); } /** * Normalizes a user-input list of mailboxes into consistent key=>value pairs. * * @param string[] $mailboxes * * @return string[] */ protected function normalizeMailboxes(array $mailboxes) { $actualMailboxes = []; foreach ($mailboxes as $key => $value) { if (\is_string($key)) { //key is email addr $address = $key; $name = $value; } else { $address = $value; $name = null; } $this->assertValidAddress($address); $actualMailboxes[$address] = $name; } return $actualMailboxes; } /** * Produces a compliant, formatted display-name based on the string given. * * @param string $displayName as displayed * @param bool $shorten the first line to make remove for header name * * @return string */ protected function createDisplayNameString($displayName, $shorten = false) { return $this->createPhrase($this, $displayName, $this->getCharset(), $this->getEncoder(), $shorten); } /** * Creates a string form of all the mailboxes in the passed array. * * @param string[] $mailboxes * * @throws Swift_RfcComplianceException * * @return string */ protected function createMailboxListString(array $mailboxes) { return implode(', ', $this->createNameAddressStrings($mailboxes)); } /** * Redefine the encoding requirements for mailboxes. * * All "specials" must be encoded as the full header value will not be quoted * * @see RFC 2822 3.2.1 * * @param string $token * * @return bool */ protected function tokenNeedsEncoding($token) { return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); } /** * Return an array of strings conforming the the name-addr spec of RFC 2822. * * @param string[] $mailboxes * * @return string[] */ private function createNameAddressStrings(array $mailboxes) { $strings = []; foreach ($mailboxes as $email => $name) { $mailboxStr = $this->addressEncoder->encodeString($email); if (null !== $name) { $nameStr = $this->createDisplayNameString($name, empty($strings)); $mailboxStr = $nameStr.' <'.$mailboxStr.'>'; } $strings[] = $mailboxStr; } return $strings; } /** * Throws an Exception if the address passed does not comply with RFC 2822. * * @param string $address * * @throws Swift_RfcComplianceException if invalid */ private function assertValidAddress($address) { if (!$this->emailValidator->isValid($address, new RFCValidation())) { throw new Swift_RfcComplianceException('Address in mailbox given ['.$address.'] does not comply with RFC 2822, 3.6.2.'); } } } swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php 0000777 00000010617 14710744267 0021436 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\MessageIDValidation; use Egulias\EmailValidator\Validation\RFCValidation; /** * An ID MIME Header for something like Message-ID or Content-ID. * * @author Chris Corbyn */ class Swift_Mime_Headers_IdentificationHeader extends Swift_Mime_Headers_AbstractHeader { /** * The IDs used in the value of this Header. * * This may hold multiple IDs or just a single ID. * * @var string[] */ private $ids = []; /** * The strict EmailValidator. * * @var EmailValidator */ private $emailValidator; private $addressEncoder; /** * Creates a new IdentificationHeader with the given $name and $id. * * @param string $name */ public function __construct($name, EmailValidator $emailValidator, Swift_AddressEncoder $addressEncoder = null) { $this->setFieldName($name); $this->emailValidator = $emailValidator; $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); } /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType() { return self::TYPE_ID; } /** * Set the model for the field body. * * This method takes a string ID, or an array of IDs. * * @param mixed $model * * @throws Swift_RfcComplianceException */ public function setFieldBodyModel($model) { $this->setId($model); } /** * Get the model for the field body. * * This method returns an array of IDs * * @return array */ public function getFieldBodyModel() { return $this->getIds(); } /** * Set the ID used in the value of this header. * * @param string|array $id * * @throws Swift_RfcComplianceException */ public function setId($id) { $this->setIds(\is_array($id) ? $id : [$id]); } /** * Get the ID used in the value of this Header. * * If multiple IDs are set only the first is returned. * * @return string */ public function getId() { if (\count($this->ids) > 0) { return $this->ids[0]; } } /** * Set a collection of IDs to use in the value of this Header. * * @param string[] $ids * * @throws Swift_RfcComplianceException */ public function setIds(array $ids) { $actualIds = []; foreach ($ids as $id) { $this->assertValidId($id); $actualIds[] = $id; } $this->clearCachedValueIf($this->ids != $actualIds); $this->ids = $actualIds; } /** * Get the list of IDs used in this Header. * * @return string[] */ public function getIds() { return $this->ids; } /** * Get the string value of the body in this Header. * * This is not necessarily RFC 2822 compliant since folding white space will * not be added at this stage (see {@see toString()} for that). * * @see toString() * * @throws Swift_RfcComplianceException * * @return string */ public function getFieldBody() { if (!$this->getCachedValue()) { $angleAddrs = []; foreach ($this->ids as $id) { $angleAddrs[] = '<'.$this->addressEncoder->encodeString($id).'>'; } $this->setCachedValue(implode(' ', $angleAddrs)); } return $this->getCachedValue(); } /** * Throws an Exception if the id passed does not comply with RFC 2822. * * @param string $id * * @throws Swift_RfcComplianceException */ private function assertValidId($id) { $emailValidation = class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation(); if (!$this->emailValidator->isValid($id, $emailValidation)) { throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>'); } } } swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php 0000777 00000034104 14710744267 0020245 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An abstract base MIME Header. * * @author Chris Corbyn */ abstract class Swift_Mime_Headers_AbstractHeader implements Swift_Mime_Header { const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)'; /** * The name of this Header. * * @var string */ private $name; /** * The Encoder used to encode this Header. * * @var Swift_Encoder */ private $encoder; /** * The maximum length of a line in the header. * * @var int */ private $lineLength = 78; /** * The language used in this Header. * * @var string */ private $lang; /** * The character set of the text in this Header. * * @var string */ private $charset = 'utf-8'; /** * The value of this Header, cached. * * @var string */ private $cachedValue = null; /** * Set the character set used in this Header. * * @param string $charset */ public function setCharset($charset) { $this->clearCachedValueIf($charset != $this->charset); $this->charset = $charset; if (isset($this->encoder)) { $this->encoder->charsetChanged($charset); } } /** * Get the character set used in this Header. * * @return string */ public function getCharset() { return $this->charset; } /** * Set the language used in this Header. * * For example, for US English, 'en-us'. * This can be unspecified. * * @param string $lang */ public function setLanguage($lang) { $this->clearCachedValueIf($this->lang != $lang); $this->lang = $lang; } /** * Get the language used in this Header. * * @return string */ public function getLanguage() { return $this->lang; } /** * Set the encoder used for encoding the header. */ public function setEncoder(Swift_Mime_HeaderEncoder $encoder) { $this->encoder = $encoder; $this->setCachedValue(null); } /** * Get the encoder used for encoding this Header. * * @return Swift_Mime_HeaderEncoder */ public function getEncoder() { return $this->encoder; } /** * Get the name of this header (e.g. charset). * * @return string */ public function getFieldName() { return $this->name; } /** * Set the maximum length of lines in the header (excluding EOL). * * @param int $lineLength */ public function setMaxLineLength($lineLength) { $this->clearCachedValueIf($this->lineLength != $lineLength); $this->lineLength = $lineLength; } /** * Get the maximum permitted length of lines in this Header. * * @return int */ public function getMaxLineLength() { return $this->lineLength; } /** * Get this Header rendered as a RFC 2822 compliant string. * * @return string * * @throws Swift_RfcComplianceException */ public function toString() { return $this->tokensToString($this->toTokens()); } /** * Returns a string representation of this object. * * @return string * * @see toString() */ public function __toString() { return $this->toString(); } /** * Set the name of this Header field. * * @param string $name */ protected function setFieldName($name) { $this->name = $name; } /** * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. * * @param string $string as displayed * @param string $charset of the text * @param bool $shorten the first line to make remove for header name * * @return string */ protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) { // Treat token as exactly what was given $phraseStr = $string; // If it's not valid if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { // .. but it is just ascii text, try escaping some characters // and make it a quoted-string if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { $phraseStr = $this->escapeSpecials($phraseStr, ['"']); $phraseStr = '"'.$phraseStr.'"'; } else { // ... otherwise it needs encoding // Determine space remaining on line if first line if ($shorten) { $usedLength = \strlen($header->getFieldName().': '); } else { $usedLength = 0; } $phraseStr = $this->encodeWords($header, $string, $usedLength); } } return $phraseStr; } /** * Escape special characters in a string (convert to quoted-pairs). * * @param string $token * @param string[] $include additional chars to escape * * @return string */ private function escapeSpecials($token, $include = []) { foreach (array_merge(['\\'], $include) as $char) { $token = str_replace($char, '\\'.$char, $token); } return $token; } /** * Encode needed word tokens within a string of input. * * @param string $input * @param string $usedLength optional * * @return string */ protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1) { $value = ''; $tokens = $this->getEncodableWordTokens($input); foreach ($tokens as $token) { // See RFC 2822, Sect 2.2 (really 2.2 ??) if ($this->tokenNeedsEncoding($token)) { // Don't encode starting WSP $firstChar = substr($token, 0, 1); switch ($firstChar) { case ' ': case "\t": $value .= $firstChar; $token = substr($token, 1); } if (-1 == $usedLength) { $usedLength = \strlen($header->getFieldName().': ') + \strlen($value); } $value .= $this->getTokenAsEncodedWord($token, $usedLength); $header->setMaxLineLength(76); // Forcefully override } else { $value .= $token; } } return $value; } /** * Test if a token needs to be encoded or not. * * @param string $token * * @return bool */ protected function tokenNeedsEncoding($token) { return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); } /** * Splits a string into tokens in blocks of words which can be encoded quickly. * * @param string $string * * @return string[] */ protected function getEncodableWordTokens($string) { $tokens = []; $encodedToken = ''; // Split at all whitespace boundaries foreach (preg_split('~(?=[\t ])~', $string ?? '') as $token) { if ($this->tokenNeedsEncoding($token)) { $encodedToken .= $token; } else { if (\strlen($encodedToken) > 0) { $tokens[] = $encodedToken; $encodedToken = ''; } $tokens[] = $token; } } if (\strlen($encodedToken)) { $tokens[] = $encodedToken; } return $tokens; } /** * Get a token as an encoded word for safe insertion into headers. * * @param string $token token to encode * @param int $firstLineOffset optional * * @return string */ protected function getTokenAsEncodedWord($token, $firstLineOffset = 0) { // Adjust $firstLineOffset to account for space needed for syntax $charsetDecl = $this->charset; if (isset($this->lang)) { $charsetDecl .= '*'.$this->lang; } $encodingWrapperLength = \strlen( '=?'.$charsetDecl.'?'.$this->encoder->getName().'??=' ); if ($firstLineOffset >= 75) { //Does this logic need to be here? $firstLineOffset = 0; } $encodedTextLines = explode("\r\n", $this->encoder->encodeString( $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->charset ) ?? '' ); if ('iso-2022-jp' !== strtolower($this->charset ?? '')) { // special encoding for iso-2022-jp using mb_encode_mimeheader foreach ($encodedTextLines as $lineNum => $line) { $encodedTextLines[$lineNum] = '=?'.$charsetDecl. '?'.$this->encoder->getName(). '?'.$line.'?='; } } return implode("\r\n ", $encodedTextLines); } /** * Generates tokens from the given string which include CRLF as individual tokens. * * @param string $token * * @return string[] */ protected function generateTokenLines($token) { return preg_split('~(\r\n)~', $token ?? '', -1, PREG_SPLIT_DELIM_CAPTURE); } /** * Set a value into the cache. * * @param string $value */ protected function setCachedValue($value) { $this->cachedValue = $value; } /** * Get the value in the cache. * * @return string */ protected function getCachedValue() { return $this->cachedValue; } /** * Clear the cached value if $condition is met. * * @param bool $condition */ protected function clearCachedValueIf($condition) { if ($condition) { $this->setCachedValue(null); } } /** * Generate a list of all tokens in the final header. * * @param string $string The string to tokenize * * @return array An array of tokens as strings */ protected function toTokens($string = null) { if (null === $string) { $string = $this->getFieldBody(); } $tokens = []; // Generate atoms; split at all invisible boundaries followed by WSP foreach (preg_split('~(?=[ \t])~', $string ?? '') as $token) { $newTokens = $this->generateTokenLines($token); foreach ($newTokens as $newToken) { $tokens[] = $newToken; } } return $tokens; } /** * Takes an array of tokens which appear in the header and turns them into * an RFC 2822 compliant string, adding FWSP where needed. * * @param string[] $tokens * * @return string */ private function tokensToString(array $tokens) { $lineCount = 0; $headerLines = []; $headerLines[] = $this->name.': '; $currentLine = &$headerLines[$lineCount++]; // Build all tokens back into compliant header foreach ($tokens as $i => $token) { // Line longer than specified maximum or token was just a new line if (("\r\n" == $token) || ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) && 0 < \strlen($currentLine)) { $headerLines[] = ''; $currentLine = &$headerLines[$lineCount++]; } // Append token to the line if ("\r\n" != $token) { $currentLine .= $token; } } // Implode with FWS (RFC 2822, 2.2.3) return implode("\r\n", $headerLines)."\r\n"; } /** * Make a deep copy of object. */ public function __clone() { if ($this->encoder) { $this->encoder = clone $this->encoder; } } } swiftmailer/lib/classes/Swift/Mime/IdGenerator.php 0000777 00000002046 14710744267 0016221 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Message ID generator. */ class Swift_Mime_IdGenerator implements Swift_IdGenerator { private $idRight; /** * @param string $idRight */ public function __construct($idRight) { $this->idRight = $idRight; } /** * Returns the right-hand side of the "@" used in all generated IDs. * * @return string */ public function getIdRight() { return $this->idRight; } /** * Sets the right-hand side of the "@" to use in all generated IDs. * * @param string $idRight */ public function setIdRight($idRight) { $this->idRight = $idRight; } /** * @return string */ public function generateId() { // 32 hex values for the left part return bin2hex(random_bytes(16)).'@'.$this->idRight; } } swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php 0000777 00000054453 14710744267 0017265 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A MIME entity, in a multipart message. * * @author Chris Corbyn */ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_CharsetObserver, Swift_Mime_EncodingObserver { /** Main message document; there can only be one of these */ const LEVEL_TOP = 16; /** An entity which nests with the same precedence as an attachment */ const LEVEL_MIXED = 256; /** An entity which nests with the same precedence as a mime part */ const LEVEL_ALTERNATIVE = 4096; /** An entity which nests with the same precedence as embedded content */ const LEVEL_RELATED = 65536; /** A collection of Headers for this mime entity */ private $headers; /** The body as a string, or a stream */ private $body; /** The encoder that encodes the body into a streamable format */ private $encoder; /** Message ID generator */ private $idGenerator; /** A mime boundary, if any is used */ private $boundary; /** Mime types to be used based on the nesting level */ private $compositeRanges = [ 'multipart/mixed' => [self::LEVEL_TOP, self::LEVEL_MIXED], 'multipart/alternative' => [self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE], 'multipart/related' => [self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED], ]; /** A set of filter rules to define what level an entity should be nested at */ private $compoundLevelFilters = []; /** The nesting level of this entity */ private $nestingLevel = self::LEVEL_ALTERNATIVE; /** A KeyCache instance used during encoding and streaming */ private $cache; /** Direct descendants of this entity */ private $immediateChildren = []; /** All descendants of this entity */ private $children = []; /** The maximum line length of the body of this entity */ private $maxLineLength = 78; /** The order in which alternative mime types should appear */ private $alternativePartOrder = [ 'text/plain' => 1, 'text/html' => 2, 'multipart/related' => 3, ]; /** The CID of this entity */ private $id; /** The key used for accessing the cache */ private $cacheKey; protected $userContentType; /** * Create a new SimpleMimeEntity with $headers, $encoder and $cache. */ public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator) { $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values $this->cache = $cache; $this->headers = $headers; $this->idGenerator = $idGenerator; $this->setEncoder($encoder); $this->headers->defineOrdering(['Content-Type', 'Content-Transfer-Encoding']); // This array specifies that, when the entire MIME document contains // $compoundLevel, then for each child within $level, if its Content-Type // is $contentType then it should be treated as if it's level is // $neededLevel instead. I tried to write that unambiguously! :-\ // Data Structure: // array ( // $compoundLevel => array( // $level => array( // $contentType => $neededLevel // ) // ) // ) $this->compoundLevelFilters = [ (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => [ self::LEVEL_ALTERNATIVE => [ 'text/plain' => self::LEVEL_ALTERNATIVE, 'text/html' => self::LEVEL_RELATED, ], ], ]; $this->id = $this->idGenerator->generateId(); } /** * Generate a new Content-ID or Message-ID for this MIME entity. * * @return string */ public function generateId() { $this->setId($this->idGenerator->generateId()); return $this->id; } /** * Get the {@link Swift_Mime_SimpleHeaderSet} for this entity. * * @return Swift_Mime_SimpleHeaderSet */ public function getHeaders() { return $this->headers; } /** * Get the nesting level of this entity. * * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE * * @return int */ public function getNestingLevel() { return $this->nestingLevel; } /** * Get the Content-type of this entity. * * @return string */ public function getContentType() { return $this->getHeaderFieldModel('Content-Type'); } /** * Get the Body Content-type of this entity. * * @return string */ public function getBodyContentType() { return $this->userContentType; } /** * Set the Content-type of this entity. * * @param string $type * * @return $this */ public function setContentType($type) { $this->setContentTypeInHeaders($type); // Keep track of the value so that if the content-type changes automatically // due to added child entities, it can be restored if they are later removed $this->userContentType = $type; return $this; } /** * Get the CID of this entity. * * The CID will only be present in headers if a Content-ID header is present. * * @return string */ public function getId() { $tmp = (array) $this->getHeaderFieldModel($this->getIdField()); return $this->headers->has($this->getIdField()) ? current($tmp) : $this->id; } /** * Set the CID of this entity. * * @param string $id * * @return $this */ public function setId($id) { if (!$this->setHeaderFieldModel($this->getIdField(), $id)) { $this->headers->addIdHeader($this->getIdField(), $id); } $this->id = $id; return $this; } /** * Get the description of this entity. * * This value comes from the Content-Description header if set. * * @return string */ public function getDescription() { return $this->getHeaderFieldModel('Content-Description'); } /** * Set the description of this entity. * * This method sets a value in the Content-ID header. * * @param string $description * * @return $this */ public function setDescription($description) { if (!$this->setHeaderFieldModel('Content-Description', $description)) { $this->headers->addTextHeader('Content-Description', $description); } return $this; } /** * Get the maximum line length of the body of this entity. * * @return int */ public function getMaxLineLength() { return $this->maxLineLength; } /** * Set the maximum line length of lines in this body. * * Though not enforced by the library, lines should not exceed 1000 chars. * * @param int $length * * @return $this */ public function setMaxLineLength($length) { $this->maxLineLength = $length; return $this; } /** * Get all children added to this entity. * * @return Swift_Mime_SimpleMimeEntity[] */ public function getChildren() { return $this->children; } /** * Set all children of this entity. * * @param Swift_Mime_SimpleMimeEntity[] $children * @param int $compoundLevel For internal use only * * @return $this */ public function setChildren(array $children, $compoundLevel = null) { // TODO: Try to refactor this logic $compoundLevel = $compoundLevel ?? $this->getCompoundLevel($children); $immediateChildren = []; $grandchildren = []; $newContentType = $this->userContentType; foreach ($children as $child) { $level = $this->getNeededChildLevel($child, $compoundLevel); if (empty($immediateChildren)) { //first iteration $immediateChildren = [$child]; } else { $nextLevel = $this->getNeededChildLevel($immediateChildren[0], $compoundLevel); if ($nextLevel == $level) { $immediateChildren[] = $child; } elseif ($level < $nextLevel) { // Re-assign immediateChildren to grandchildren $grandchildren = array_merge($grandchildren, $immediateChildren); // Set new children $immediateChildren = [$child]; } else { $grandchildren[] = $child; } } } if ($immediateChildren) { $lowestLevel = $this->getNeededChildLevel($immediateChildren[0], $compoundLevel); // Determine which composite media type is needed to accommodate the // immediate children foreach ($this->compositeRanges as $mediaType => $range) { if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) { $newContentType = $mediaType; break; } } // Put any grandchildren in a subpart if (!empty($grandchildren)) { $subentity = $this->createChild(); $subentity->setNestingLevel($lowestLevel); $subentity->setChildren($grandchildren, $compoundLevel); array_unshift($immediateChildren, $subentity); } } $this->immediateChildren = $immediateChildren; $this->children = $children; $this->setContentTypeInHeaders($newContentType); $this->fixHeaders(); $this->sortChildren(); return $this; } /** * Get the body of this entity as a string. * * @return string */ public function getBody() { return $this->body instanceof Swift_OutputByteStream ? $this->readStream($this->body) : $this->body; } /** * Set the body of this entity, either as a string, or as an instance of * {@link Swift_OutputByteStream}. * * @param mixed $body * @param string $contentType optional * * @return $this */ public function setBody($body, $contentType = null) { if ($body !== $this->body) { $this->clearCache(); } $this->body = $body; if (null !== $contentType) { $this->setContentType($contentType); } return $this; } /** * Get the encoder used for the body of this entity. * * @return Swift_Mime_ContentEncoder */ public function getEncoder() { return $this->encoder; } /** * Set the encoder used for the body of this entity. * * @return $this */ public function setEncoder(Swift_Mime_ContentEncoder $encoder) { if ($encoder !== $this->encoder) { $this->clearCache(); } $this->encoder = $encoder; $this->setEncoding($encoder->getName()); $this->notifyEncoderChanged($encoder); return $this; } /** * Get the boundary used to separate children in this entity. * * @return string */ public function getBoundary() { if (!isset($this->boundary)) { $this->boundary = '_=_swift_'.time().'_'.bin2hex(random_bytes(16)).'_=_'; } return $this->boundary; } /** * Set the boundary used to separate children in this entity. * * @param string $boundary * * @throws Swift_RfcComplianceException * * @return $this */ public function setBoundary($boundary) { $this->assertValidBoundary($boundary); $this->boundary = $boundary; return $this; } /** * Receive notification that the charset of this entity, or a parent entity * has changed. * * @param string $charset */ public function charsetChanged($charset) { $this->notifyCharsetChanged($charset); } /** * Receive notification that the encoder of this entity or a parent entity * has changed. */ public function encoderChanged(Swift_Mime_ContentEncoder $encoder) { $this->notifyEncoderChanged($encoder); } /** * Get this entire entity as a string. * * @return string */ public function toString() { $string = $this->headers->toString(); $string .= $this->bodyToString(); return $string; } /** * Get this entire entity as a string. * * @return string */ protected function bodyToString() { $string = ''; if (isset($this->body) && empty($this->immediateChildren)) { if ($this->cache->hasKey($this->cacheKey, 'body')) { $body = $this->cache->getString($this->cacheKey, 'body'); } else { $body = "\r\n".$this->encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()); $this->cache->setString($this->cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE); } $string .= $body; } if (!empty($this->immediateChildren)) { foreach ($this->immediateChildren as $child) { $string .= "\r\n\r\n--".$this->getBoundary()."\r\n"; $string .= $child->toString(); } $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n"; } return $string; } /** * Returns a string representation of this object. * * @see toString() * * @return string */ public function __toString() { return $this->toString(); } /** * Write this entire entity to a {@see Swift_InputByteStream}. */ public function toByteStream(Swift_InputByteStream $is) { $is->write($this->headers->toString()); $is->commit(); $this->bodyToByteStream($is); } /** * Write this entire entity to a {@link Swift_InputByteStream}. */ protected function bodyToByteStream(Swift_InputByteStream $is) { if (empty($this->immediateChildren)) { if (isset($this->body)) { if ($this->cache->hasKey($this->cacheKey, 'body')) { $this->cache->exportToByteStream($this->cacheKey, 'body', $is); } else { $cacheIs = $this->cache->getInputByteStream($this->cacheKey, 'body'); if ($cacheIs) { $is->bind($cacheIs); } $is->write("\r\n"); if ($this->body instanceof Swift_OutputByteStream) { $this->body->setReadPointer(0); $this->encoder->encodeByteStream($this->body, $is, 0, $this->getMaxLineLength()); } else { $is->write($this->encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength())); } if ($cacheIs) { $is->unbind($cacheIs); } } } } if (!empty($this->immediateChildren)) { foreach ($this->immediateChildren as $child) { $is->write("\r\n\r\n--".$this->getBoundary()."\r\n"); $child->toByteStream($is); } $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n"); } } /** * Get the name of the header that provides the ID of this entity. */ protected function getIdField() { return 'Content-ID'; } /** * Get the model data (usually an array or a string) for $field. */ protected function getHeaderFieldModel($field) { if ($this->headers->has($field)) { return $this->headers->get($field)->getFieldBodyModel(); } } /** * Set the model data for $field. */ protected function setHeaderFieldModel($field, $model) { if ($this->headers->has($field)) { $this->headers->get($field)->setFieldBodyModel($model); return true; } return false; } /** * Get the parameter value of $parameter on $field header. */ protected function getHeaderParameter($field, $parameter) { if ($this->headers->has($field)) { return $this->headers->get($field)->getParameter($parameter); } } /** * Set the parameter value of $parameter on $field header. */ protected function setHeaderParameter($field, $parameter, $value) { if ($this->headers->has($field)) { $this->headers->get($field)->setParameter($parameter, $value); return true; } return false; } /** * Re-evaluate what content type and encoding should be used on this entity. */ protected function fixHeaders() { if (\count($this->immediateChildren)) { $this->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary() ); $this->headers->remove('Content-Transfer-Encoding'); } else { $this->setHeaderParameter('Content-Type', 'boundary', null); $this->setEncoding($this->encoder->getName()); } } /** * Get the KeyCache used in this entity. * * @return Swift_KeyCache */ protected function getCache() { return $this->cache; } /** * Get the ID generator. * * @return Swift_IdGenerator */ protected function getIdGenerator() { return $this->idGenerator; } /** * Empty the KeyCache for this entity. */ protected function clearCache() { $this->cache->clearKey($this->cacheKey, 'body'); } private function readStream(Swift_OutputByteStream $os) { $string = ''; while (false !== $bytes = $os->read(8192)) { $string .= $bytes; } $os->setReadPointer(0); return $string; } private function setEncoding($encoding) { if (!$this->setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) { $this->headers->addTextHeader('Content-Transfer-Encoding', $encoding); } } private function assertValidBoundary($boundary) { if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) { throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.'); } } private function setContentTypeInHeaders($type) { if (!$this->setHeaderFieldModel('Content-Type', $type)) { $this->headers->addParameterizedHeader('Content-Type', $type); } } private function setNestingLevel($level) { $this->nestingLevel = $level; } private function getCompoundLevel($children) { $level = 0; foreach ($children as $child) { $level |= $child->getNestingLevel(); } return $level; } private function getNeededChildLevel($child, $compoundLevel) { $filter = []; foreach ($this->compoundLevelFilters as $bitmask => $rules) { if (($compoundLevel & $bitmask) === $bitmask) { $filter = $rules + $filter; } } $realLevel = $child->getNestingLevel(); $lowercaseType = strtolower($child->getContentType() ?? ''); if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) { return $filter[$realLevel][$lowercaseType]; } return $realLevel; } private function createChild() { return new self($this->headers->newInstance(), $this->encoder, $this->cache, $this->idGenerator); } private function notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder) { foreach ($this->immediateChildren as $child) { $child->encoderChanged($encoder); } } private function notifyCharsetChanged($charset) { $this->encoder->charsetChanged($charset); $this->headers->charsetChanged($charset); foreach ($this->immediateChildren as $child) { $child->charsetChanged($charset); } } private function sortChildren() { $shouldSort = false; foreach ($this->immediateChildren as $child) { // NOTE: This include alternative parts moved into a related part if (self::LEVEL_ALTERNATIVE == $child->getNestingLevel()) { $shouldSort = true; break; } } // Sort in order of preference, if there is one if ($shouldSort) { // Group the messages by order of preference $sorted = []; foreach ($this->immediateChildren as $child) { $type = $child->getContentType(); $level = \array_key_exists($type, $this->alternativePartOrder) ? $this->alternativePartOrder[$type] : max($this->alternativePartOrder) + 1; if (empty($sorted[$level])) { $sorted[$level] = []; } $sorted[$level][] = $child; } ksort($sorted); $this->immediateChildren = array_reduce($sorted, 'array_merge', []); } } /** * Empties it's own contents from the cache. */ public function __destruct() { if ($this->cache instanceof Swift_KeyCache) { $this->cache->clearAll($this->cacheKey); } } /** * Make a deep copy of object. */ public function __clone() { $this->headers = clone $this->headers; $this->encoder = clone $this->encoder; $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values $children = []; foreach ($this->children as $pos => $child) { $children[$pos] = clone $child; } $this->setChildren($children); } public function __wakeup() { $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values $this->cache = new Swift_KeyCache_ArrayKeyCache(new Swift_KeyCache_SimpleKeyCacheInputStream()); } } swiftmailer/lib/classes/Swift/Mime/Header.php 0000777 00000003715 14710744267 0015212 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A MIME Header. * * @author Chris Corbyn */ interface Swift_Mime_Header { /** Text headers */ const TYPE_TEXT = 2; /** headers (text + params) */ const TYPE_PARAMETERIZED = 6; /** Mailbox and address headers */ const TYPE_MAILBOX = 8; /** Date and time headers */ const TYPE_DATE = 16; /** Identification headers */ const TYPE_ID = 32; /** Address path headers */ const TYPE_PATH = 64; /** * Get the type of Header that this instance represents. * * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX * @see TYPE_DATE, TYPE_ID, TYPE_PATH * * @return int */ public function getFieldType(); /** * Set the model for the field body. * * The actual types needed will vary depending upon the type of Header. * * @param mixed $model */ public function setFieldBodyModel($model); /** * Set the charset used when rendering the Header. * * @param string $charset */ public function setCharset($charset); /** * Get the model for the field body. * * The return type depends on the specifics of the Header. * * @return mixed */ public function getFieldBodyModel(); /** * Get the name of this header (e.g. Subject). * * The name is an identifier and as such will be immutable. * * @return string */ public function getFieldName(); /** * Get the field body, prepared for folding into a final header value. * * @return string */ public function getFieldBody(); /** * Get this Header rendered as a compliant string, including trailing CRLF. * * @return string */ public function toString(); } swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php 0000777 00000000750 14710744267 0016506 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Interface for all Header Encoding schemes. * * @author Chris Corbyn */ interface Swift_Mime_HeaderEncoder extends Swift_Encoder { /** * Get the MIME name of this content encoding scheme. * * @return string */ public function getName(); } swiftmailer/lib/classes/Swift/Mime/Attachment.php 0000777 00000006767 14710744267 0016124 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An attachment, in a multipart message. * * @author Chris Corbyn */ class Swift_Mime_Attachment extends Swift_Mime_SimpleMimeEntity { /** Recognized MIME types */ private $mimeTypes = []; /** * Create a new Attachment with $headers, $encoder and $cache. * * @param array $mimeTypes */ public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator, $mimeTypes = []) { parent::__construct($headers, $encoder, $cache, $idGenerator); $this->setDisposition('attachment'); $this->setContentType('application/octet-stream'); $this->mimeTypes = $mimeTypes; } /** * Get the nesting level used for this attachment. * * Always returns {@link LEVEL_MIXED}. * * @return int */ public function getNestingLevel() { return self::LEVEL_MIXED; } /** * Get the Content-Disposition of this attachment. * * By default attachments have a disposition of "attachment". * * @return string */ public function getDisposition() { return $this->getHeaderFieldModel('Content-Disposition'); } /** * Set the Content-Disposition of this attachment. * * @param string $disposition * * @return $this */ public function setDisposition($disposition) { if (!$this->setHeaderFieldModel('Content-Disposition', $disposition)) { $this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition); } return $this; } /** * Get the filename of this attachment when downloaded. * * @return string */ public function getFilename() { return $this->getHeaderParameter('Content-Disposition', 'filename'); } /** * Set the filename of this attachment. * * @param string $filename * * @return $this */ public function setFilename($filename) { $this->setHeaderParameter('Content-Disposition', 'filename', $filename); $this->setHeaderParameter('Content-Type', 'name', $filename); return $this; } /** * Get the file size of this attachment. * * @return int */ public function getSize() { return $this->getHeaderParameter('Content-Disposition', 'size'); } /** * Set the file size of this attachment. * * @param int $size * * @return $this */ public function setSize($size) { $this->setHeaderParameter('Content-Disposition', 'size', $size); return $this; } /** * Set the file that this attachment is for. * * @param string $contentType optional * * @return $this */ public function setFile(Swift_FileStream $file, $contentType = null) { $this->setFilename(basename($file->getPath())); $this->setBody($file, $contentType); if (!isset($contentType)) { $extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1)); if (\array_key_exists($extension, $this->mimeTypes)) { $this->setContentType($this->mimeTypes[$extension]); } } return $this; } } swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php 0000777 00000002036 14710744267 0016306 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An embedded file, in a multipart message. * * @author Chris Corbyn */ class Swift_Mime_EmbeddedFile extends Swift_Mime_Attachment { /** * Creates a new Attachment with $headers and $encoder. * * @param array $mimeTypes optional */ public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator, $mimeTypes = []) { parent::__construct($headers, $encoder, $cache, $idGenerator, $mimeTypes); $this->setDisposition('inline'); $this->setId($this->getId()); } /** * Get the nesting level of this EmbeddedFile. * * Returns {@see LEVEL_RELATED}. * * @return int */ public function getNestingLevel() { return self::LEVEL_RELATED; } } swiftmailer/lib/classes/Swift/Mime/MimePart.php 0000777 00000011714 14710744267 0015536 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A MIME part, in a multipart message. * * @author Chris Corbyn */ class Swift_Mime_MimePart extends Swift_Mime_SimpleMimeEntity { /** The format parameter last specified by the user */ protected $userFormat; /** The charset last specified by the user */ protected $userCharset; /** The delsp parameter last specified by the user */ protected $userDelSp; /** The nesting level of this MimePart */ private $nestingLevel = self::LEVEL_ALTERNATIVE; /** * Create a new MimePart with $headers, $encoder and $cache. * * @param string $charset */ public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator, $charset = null) { parent::__construct($headers, $encoder, $cache, $idGenerator); $this->setContentType('text/plain'); if (null !== $charset) { $this->setCharset($charset); } } /** * Set the body of this entity, either as a string, or as an instance of * {@link Swift_OutputByteStream}. * * @param mixed $body * @param string $contentType optional * @param string $charset optional * * @return $this */ public function setBody($body, $contentType = null, $charset = null) { if (isset($charset)) { $this->setCharset($charset); } $body = $this->convertString($body); parent::setBody($body, $contentType); return $this; } /** * Get the character set of this entity. * * @return string */ public function getCharset() { return $this->getHeaderParameter('Content-Type', 'charset'); } /** * Set the character set of this entity. * * @param string $charset * * @return $this */ public function setCharset($charset) { $this->setHeaderParameter('Content-Type', 'charset', $charset); if ($charset !== $this->userCharset) { $this->clearCache(); } $this->userCharset = $charset; parent::charsetChanged($charset); return $this; } /** * Get the format of this entity (i.e. flowed or fixed). * * @return string */ public function getFormat() { return $this->getHeaderParameter('Content-Type', 'format'); } /** * Set the format of this entity (flowed or fixed). * * @param string $format * * @return $this */ public function setFormat($format) { $this->setHeaderParameter('Content-Type', 'format', $format); $this->userFormat = $format; return $this; } /** * Test if delsp is being used for this entity. * * @return bool */ public function getDelSp() { return 'yes' === $this->getHeaderParameter('Content-Type', 'delsp'); } /** * Turn delsp on or off for this entity. * * @param bool $delsp * * @return $this */ public function setDelSp($delsp = true) { $this->setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null); $this->userDelSp = $delsp; return $this; } /** * Get the nesting level of this entity. * * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED * * @return int */ public function getNestingLevel() { return $this->nestingLevel; } /** * Receive notification that the charset has changed on this document, or a * parent document. * * @param string $charset */ public function charsetChanged($charset) { $this->setCharset($charset); } /** Fix the content-type and encoding of this entity */ protected function fixHeaders() { parent::fixHeaders(); if (\count($this->getChildren())) { $this->setHeaderParameter('Content-Type', 'charset', null); $this->setHeaderParameter('Content-Type', 'format', null); $this->setHeaderParameter('Content-Type', 'delsp', null); } else { $this->setCharset($this->userCharset); $this->setFormat($this->userFormat); $this->setDelSp($this->userDelSp); } } /** Set the nesting level of this entity */ protected function setNestingLevel($level) { $this->nestingLevel = $level; } /** Encode charset when charset is not utf-8 */ protected function convertString($string) { $charset = strtolower($this->getCharset() ?? ''); if (!\in_array($charset, ['utf-8', 'iso-8859-1', 'iso-8859-15', ''])) { return mb_convert_encoding($string, $charset, 'utf-8'); } return $string; } } swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php 0000777 00000000775 14710744267 0017126 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Observes changes in an Mime entity's character set. * * @author Chris Corbyn */ interface Swift_Mime_CharsetObserver { /** * Notify this observer that the entity's charset has changed. * * @param string $charset */ public function charsetChanged($charset); } swiftmailer/lib/classes/Swift/Mime/ContentEncoder.php 0000777 00000001711 14710744267 0016726 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Interface for all Transfer Encoding schemes. * * @author Chris Corbyn */ interface Swift_Mime_ContentEncoder extends Swift_Encoder { /** * Encode $in to $out. * * @param Swift_OutputByteStream $os to read from * @param Swift_InputByteStream $is to write to * @param int $firstLineOffset * @param int $maxLineLength - 0 indicates the default length for this encoding */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0); /** * Get the MIME name of this content encoding scheme. * * @return string */ public function getName(); } swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php 0000777 00000001004 14710744267 0017245 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Observes changes for a Mime entity's ContentEncoder. * * @author Chris Corbyn */ interface Swift_Mime_EncodingObserver { /** * Notify this observer that the observed entity's ContentEncoder has changed. */ public function encoderChanged(Swift_Mime_ContentEncoder $encoder); } swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php 0000777 00000003123 14710744267 0022140 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Base64 (B) Header Encoding in Swift Mailer. * * @author Chris Corbyn */ class Swift_Mime_HeaderEncoder_Base64HeaderEncoder extends Swift_Encoder_Base64Encoder implements Swift_Mime_HeaderEncoder { /** * Get the name of this encoding scheme. * Returns the string 'B'. * * @return string */ public function getName() { return 'B'; } /** * Takes an unencoded string and produces a Base64 encoded string from it. * * If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of * default encodeString, otherwise pass to the parent method. * * @param string $string string to encode * @param int $firstLineOffset * @param int $maxLineLength optional, 0 indicates the default of 76 bytes * @param string $charset * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0, $charset = 'utf-8') { if ('iso-2022-jp' === strtolower($charset ?? '')) { $old = mb_internal_encoding(); mb_internal_encoding('utf-8'); $newstring = mb_encode_mimeheader($string, $charset, $this->getName(), "\r\n"); mb_internal_encoding($old); return $newstring; } return parent::encodeString($string, $firstLineOffset, $maxLineLength); } } swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php 0000777 00000003336 14710744267 0021502 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Quoted Printable (Q) Header Encoding in Swift Mailer. * * @author Chris Corbyn */ class Swift_Mime_HeaderEncoder_QpHeaderEncoder extends Swift_Encoder_QpEncoder implements Swift_Mime_HeaderEncoder { /** * Creates a new QpHeaderEncoder for the given CharacterStream. * * @param Swift_CharacterStream $charStream to use for reading characters */ public function __construct(Swift_CharacterStream $charStream) { parent::__construct($charStream); } protected function initSafeMap() { foreach (array_merge( range(0x61, 0x7A), range(0x41, 0x5A), range(0x30, 0x39), [0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F] ) as $byte) { $this->safeMap[$byte] = \chr($byte); } } /** * Get the name of this encoding scheme. * * Returns the string 'Q'. * * @return string */ public function getName() { return 'Q'; } /** * Takes an unencoded string and produces a QP encoded string from it. * * @param string $string string to encode * @param int $firstLineOffset optional * @param int $maxLineLength optional, 0 indicates the default of 76 chars * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], parent::encodeString($string, $firstLineOffset, $maxLineLength) ); } } swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php 0000777 00000012364 14710744267 0017714 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ use Egulias\EmailValidator\EmailValidator; /** * Creates MIME headers. * * @author Chris Corbyn */ class Swift_Mime_SimpleHeaderFactory implements Swift_Mime_CharsetObserver { /** The HeaderEncoder used by these headers */ private $encoder; /** The Encoder used by parameters */ private $paramEncoder; /** Strict EmailValidator */ private $emailValidator; /** The charset of created Headers */ private $charset; /** Swift_AddressEncoder */ private $addressEncoder; /** * Creates a new SimpleHeaderFactory using $encoder and $paramEncoder. * * @param string|null $charset */ public function __construct(Swift_Mime_HeaderEncoder $encoder, Swift_Encoder $paramEncoder, EmailValidator $emailValidator, $charset = null, Swift_AddressEncoder $addressEncoder = null) { $this->encoder = $encoder; $this->paramEncoder = $paramEncoder; $this->emailValidator = $emailValidator; $this->charset = $charset; $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder(); } /** * Create a new Mailbox Header with a list of $addresses. * * @param string $name * @param array|string|null $addresses * * @return Swift_Mime_Header */ public function createMailboxHeader($name, $addresses = null) { $header = new Swift_Mime_Headers_MailboxHeader($name, $this->encoder, $this->emailValidator, $this->addressEncoder); if (isset($addresses)) { $header->setFieldBodyModel($addresses); } $this->setHeaderCharset($header); return $header; } /** * Create a new Date header using $dateTime. * * @param string $name * * @return Swift_Mime_Header */ public function createDateHeader($name, DateTimeInterface $dateTime = null) { $header = new Swift_Mime_Headers_DateHeader($name); if (isset($dateTime)) { $header->setFieldBodyModel($dateTime); } $this->setHeaderCharset($header); return $header; } /** * Create a new basic text header with $name and $value. * * @param string $name * @param string $value * * @return Swift_Mime_Header */ public function createTextHeader($name, $value = null) { $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->encoder); if (isset($value)) { $header->setFieldBodyModel($value); } $this->setHeaderCharset($header); return $header; } /** * Create a new ParameterizedHeader with $name, $value and $params. * * @param string $name * @param string $value * @param array $params * * @return Swift_Mime_Headers_ParameterizedHeader */ public function createParameterizedHeader($name, $value = null, $params = []) { $header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->encoder, ('content-disposition' == strtolower($name ?? '')) ? $this->paramEncoder : null); if (isset($value)) { $header->setFieldBodyModel($value); } foreach ($params as $k => $v) { $header->setParameter($k, $v); } $this->setHeaderCharset($header); return $header; } /** * Create a new ID header for Message-ID or Content-ID. * * @param string $name * @param string|array $ids * * @return Swift_Mime_Header */ public function createIdHeader($name, $ids = null) { $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->emailValidator); if (isset($ids)) { $header->setFieldBodyModel($ids); } $this->setHeaderCharset($header); return $header; } /** * Create a new Path header with an address (path) in it. * * @param string $name * @param string $path * * @return Swift_Mime_Header */ public function createPathHeader($name, $path = null) { $header = new Swift_Mime_Headers_PathHeader($name, $this->emailValidator); if (isset($path)) { $header->setFieldBodyModel($path); } $this->setHeaderCharset($header); return $header; } /** * Notify this observer that the entity's charset has changed. * * @param string $charset */ public function charsetChanged($charset) { $this->charset = $charset; $this->encoder->charsetChanged($charset); $this->paramEncoder->charsetChanged($charset); } /** * Make a deep copy of object. */ public function __clone() { $this->encoder = clone $this->encoder; $this->paramEncoder = clone $this->paramEncoder; $this->addressEncoder = clone $this->addressEncoder; } /** Apply the charset to the Header */ private function setHeaderCharset(Swift_Mime_Header $header) { if (isset($this->charset)) { $header->setCharset($this->charset); } } } swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php 0000777 00000024257 14710744267 0017044 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A collection of MIME headers. * * @author Chris Corbyn */ class Swift_Mime_SimpleHeaderSet implements Swift_Mime_CharsetObserver { /** HeaderFactory */ private $factory; /** Collection of set Headers */ private $headers = []; /** Field ordering details */ private $order = []; /** List of fields which are required to be displayed */ private $required = []; /** The charset used by Headers */ private $charset; /** * Create a new SimpleHeaderSet with the given $factory. * * @param string $charset */ public function __construct(Swift_Mime_SimpleHeaderFactory $factory, $charset = null) { $this->factory = $factory; if (isset($charset)) { $this->setCharset($charset); } } public function newInstance() { return new self($this->factory); } /** * Set the charset used by these headers. * * @param string $charset */ public function setCharset($charset) { $this->charset = $charset; $this->factory->charsetChanged($charset); $this->notifyHeadersOfCharset($charset); } /** * Add a new Mailbox Header with a list of $addresses. * * @param string $name * @param array|string $addresses */ public function addMailboxHeader($name, $addresses = null) { $this->storeHeader($name, $this->factory->createMailboxHeader($name, $addresses)); } /** * Add a new Date header using $dateTime. * * @param string $name */ public function addDateHeader($name, DateTimeInterface $dateTime = null) { $this->storeHeader($name, $this->factory->createDateHeader($name, $dateTime)); } /** * Add a new basic text header with $name and $value. * * @param string $name * @param string $value */ public function addTextHeader($name, $value = null) { $this->storeHeader($name, $this->factory->createTextHeader($name, $value)); } /** * Add a new ParameterizedHeader with $name, $value and $params. * * @param string $name * @param string $value * @param array $params */ public function addParameterizedHeader($name, $value = null, $params = []) { $this->storeHeader($name, $this->factory->createParameterizedHeader($name, $value, $params)); } /** * Add a new ID header for Message-ID or Content-ID. * * @param string $name * @param string|array $ids */ public function addIdHeader($name, $ids = null) { $this->storeHeader($name, $this->factory->createIdHeader($name, $ids)); } /** * Add a new Path header with an address (path) in it. * * @param string $name * @param string $path */ public function addPathHeader($name, $path = null) { $this->storeHeader($name, $this->factory->createPathHeader($name, $path)); } /** * Returns true if at least one header with the given $name exists. * * If multiple headers match, the actual one may be specified by $index. * * @param string $name * @param int $index * * @return bool */ public function has($name, $index = 0) { $lowerName = strtolower($name ?? ''); if (!\array_key_exists($lowerName, $this->headers)) { return false; } if (\func_num_args() < 2) { // index was not specified, so we only need to check that there is at least one header value set return (bool) \count($this->headers[$lowerName]); } return \array_key_exists($index, $this->headers[$lowerName]); } /** * Set a header in the HeaderSet. * * The header may be a previously fetched header via {@link get()} or it may * be one that has been created separately. * * If $index is specified, the header will be inserted into the set at this * offset. * * @param int $index */ public function set(Swift_Mime_Header $header, $index = 0) { $this->storeHeader($header->getFieldName(), $header, $index); } /** * Get the header with the given $name. * * If multiple headers match, the actual one may be specified by $index. * Returns NULL if none present. * * @param string $name * @param int $index * * @return Swift_Mime_Header|null */ public function get($name, $index = 0) { $name = strtolower($name ?? ''); if (\func_num_args() < 2) { if ($this->has($name)) { $values = array_values($this->headers[$name]); return array_shift($values); } } else { if ($this->has($name, $index)) { return $this->headers[$name][$index]; } } } /** * Get all headers with the given $name. * * @param string $name * * @return array */ public function getAll($name = null) { if (!isset($name)) { $headers = []; foreach ($this->headers as $collection) { $headers = array_merge($headers, $collection); } return $headers; } $lowerName = strtolower($name ?? ''); if (!\array_key_exists($lowerName, $this->headers)) { return []; } return $this->headers[$lowerName]; } /** * Return the name of all Headers. * * @return array */ public function listAll() { $headers = $this->headers; if ($this->canSort()) { uksort($headers, [$this, 'sortHeaders']); } return array_keys($headers); } /** * Remove the header with the given $name if it's set. * * If multiple headers match, the actual one may be specified by $index. * * @param string $name * @param int $index */ public function remove($name, $index = 0) { $lowerName = strtolower($name ?? ''); unset($this->headers[$lowerName][$index]); } /** * Remove all headers with the given $name. * * @param string $name */ public function removeAll($name) { $lowerName = strtolower($name ?? ''); unset($this->headers[$lowerName]); } /** * Define a list of Header names as an array in the correct order. * * These Headers will be output in the given order where present. */ public function defineOrdering(array $sequence) { $this->order = array_flip(array_map('strtolower', $sequence)); } /** * Set a list of header names which must always be displayed when set. * * Usually headers without a field value won't be output unless set here. */ public function setAlwaysDisplayed(array $names) { $this->required = array_flip(array_map('strtolower', $names)); } /** * Notify this observer that the entity's charset has changed. * * @param string $charset */ public function charsetChanged($charset) { $this->setCharset($charset); } /** * Returns a string with a representation of all headers. * * @return string */ public function toString() { $string = ''; $headers = $this->headers; if ($this->canSort()) { uksort($headers, [$this, 'sortHeaders']); } foreach ($headers as $collection) { foreach ($collection as $header) { if ($this->isDisplayed($header) || '' != $header->getFieldBody()) { $string .= $header->toString(); } } } return $string; } /** * Returns a string representation of this object. * * @return string * * @see toString() */ public function __toString() { return $this->toString(); } /** Save a Header to the internal collection */ private function storeHeader($name, Swift_Mime_Header $header, $offset = null) { if (!isset($this->headers[strtolower($name ?? '')])) { $this->headers[strtolower($name ?? '')] = []; } if (!isset($offset)) { $this->headers[strtolower($name ?? '')][] = $header; } else { $this->headers[strtolower($name ?? '')][$offset] = $header; } } /** Test if the headers can be sorted */ private function canSort() { return \count($this->order) > 0; } /** uksort() algorithm for Header ordering */ private function sortHeaders($a, $b) { $lowerA = strtolower($a ?? ''); $lowerB = strtolower($b ?? ''); $aPos = \array_key_exists($lowerA, $this->order) ? $this->order[$lowerA] : -1; $bPos = \array_key_exists($lowerB, $this->order) ? $this->order[$lowerB] : -1; if (-1 === $aPos && -1 === $bPos) { // just be sure to be determinist here return $a > $b ? -1 : 1; } if (-1 == $aPos) { return 1; } elseif (-1 == $bPos) { return -1; } return $aPos < $bPos ? -1 : 1; } /** Test if the given Header is always displayed */ private function isDisplayed(Swift_Mime_Header $header) { return \array_key_exists(strtolower($header->getFieldName() ?? ''), $this->required); } /** Notify all Headers of the new charset */ private function notifyHeadersOfCharset($charset) { foreach ($this->headers as $headerGroup) { foreach ($headerGroup as $header) { $header->setCharset($charset); } } } /** * Make a deep copy of object. */ public function __clone() { $this->factory = clone $this->factory; foreach ($this->headers as $groupKey => $headerGroup) { foreach ($headerGroup as $key => $header) { $this->headers[$groupKey][$key] = clone $header; } } } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php 0000777 00000010154 14710744267 0022142 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Quoted Printable (QP) Transfer Encoding in Swift Mailer. * * @author Chris Corbyn */ class Swift_Mime_ContentEncoder_QpContentEncoder extends Swift_Encoder_QpEncoder implements Swift_Mime_ContentEncoder { protected $dotEscape; /** * Creates a new QpContentEncoder for the given CharacterStream. * * @param Swift_CharacterStream $charStream to use for reading characters * @param Swift_StreamFilter $filter if canonicalization should occur * @param bool $dotEscape if dot stuffing workaround must be enabled */ public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null, $dotEscape = false) { $this->dotEscape = $dotEscape; parent::__construct($charStream, $filter); } public function __sleep() { return ['charStream', 'filter', 'dotEscape']; } protected function getSafeMapShareId() { return static::class.($this->dotEscape ? '.dotEscape' : ''); } protected function initSafeMap() { parent::initSafeMap(); if ($this->dotEscape) { /* Encode . as =2e for buggy remote servers */ unset($this->safeMap[0x2e]); } } /** * Encode stream $in to stream $out. * * QP encoded strings have a maximum line length of 76 characters. * If the first line needs to be shorter, indicate the difference with * $firstLineOffset. * * @param Swift_OutputByteStream $os output stream * @param Swift_InputByteStream $is input stream * @param int $firstLineOffset * @param int $maxLineLength */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { if ($maxLineLength > 76 || $maxLineLength <= 0) { $maxLineLength = 76; } $thisLineLength = $maxLineLength - $firstLineOffset; $this->charStream->flushContents(); $this->charStream->importByteStream($os); $currentLine = ''; $prepend = ''; $size = $lineLen = 0; while (false !== $bytes = $this->nextSequence()) { // If we're filtering the input if (isset($this->filter)) { // If we can't filter because we need more bytes while ($this->filter->shouldBuffer($bytes)) { // Then collect bytes into the buffer if (false === $moreBytes = $this->nextSequence(1)) { break; } foreach ($moreBytes as $b) { $bytes[] = $b; } } // And filter them $bytes = $this->filter->filter($bytes); } $enc = $this->encodeByteSequence($bytes, $size); $i = strpos($enc, '=0D=0A'); $newLineLength = $lineLen + (false === $i ? $size : $i); if ($currentLine && $newLineLength >= $thisLineLength) { $is->write($prepend.$this->standardize($currentLine)); $currentLine = ''; $prepend = "=\r\n"; $thisLineLength = $maxLineLength; $lineLen = 0; } $currentLine .= $enc; if (false === $i) { $lineLen += $size; } else { // 6 is the length of '=0D=0A'. $lineLen = $size - strrpos($enc, '=0D=0A') - 6; } } if (\strlen($currentLine)) { $is->write($prepend.$this->standardize($currentLine)); } } /** * Get the name of this encoding scheme. * Returns the string 'quoted-printable'. * * @return string */ public function getName() { return 'quoted-printable'; } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php 0000777 00000010210 14710744267 0022616 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles binary/7/8-bit Transfer Encoding in Swift Mailer. * * When sending 8-bit content over SMTP, you should use * Swift_Transport_Esmtp_EightBitMimeHandler to enable the 8BITMIME SMTP * extension. * * @author Chris Corbyn */ class Swift_Mime_ContentEncoder_PlainContentEncoder implements Swift_Mime_ContentEncoder { /** * The name of this encoding scheme (probably 7bit or 8bit). * * @var string */ private $name; /** * True if canonical transformations should be done. * * @var bool */ private $canonical; /** * Creates a new PlainContentEncoder with $name (probably 7bit or 8bit). * * @param string $name * @param bool $canonical if canonicalization transformation should be done */ public function __construct($name, $canonical = false) { $this->name = $name; $this->canonical = $canonical; } /** * Encode a given string to produce an encoded string. * * @param string $string * @param int $firstLineOffset ignored * @param int $maxLineLength - 0 means no wrapping will occur * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { if ($this->canonical) { $string = $this->canonicalize($string); } return $this->safeWordwrap($string, $maxLineLength, "\r\n"); } /** * Encode stream $in to stream $out. * * @param int $firstLineOffset ignored * @param int $maxLineLength optional, 0 means no wrapping will occur */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { $leftOver = ''; while (false !== $bytes = $os->read(8192)) { $toencode = $leftOver.$bytes; if ($this->canonical) { $toencode = $this->canonicalize($toencode); } $wrapped = $this->safeWordwrap($toencode, $maxLineLength, "\r\n"); $lastLinePos = strrpos($wrapped, "\r\n"); $leftOver = substr($wrapped, $lastLinePos); $wrapped = substr($wrapped, 0, $lastLinePos); $is->write($wrapped); } if (\strlen($leftOver)) { $is->write($leftOver); } } /** * Get the name of this encoding scheme. * * @return string */ public function getName() { return $this->name; } /** * Not used. */ public function charsetChanged($charset) { } /** * A safer (but weaker) wordwrap for unicode. * * @param string $string * @param int $length * @param string $le * * @return string */ private function safeWordwrap($string, $length = 75, $le = "\r\n") { if (0 >= $length) { return $string; } $originalLines = explode($le, $string); $lines = []; $lineCount = 0; foreach ($originalLines as $originalLine) { $lines[] = ''; $currentLine = &$lines[$lineCount++]; //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine); $chunks = preg_split('/(?<=\s)/', $originalLine); foreach ($chunks as $chunk) { if (0 != \strlen($currentLine) && \strlen($currentLine.$chunk) > $length) { $lines[] = ''; $currentLine = &$lines[$lineCount++]; } $currentLine .= $chunk; } } return implode("\r\n", $lines); } /** * Canonicalize string input (fix CRLF). * * @param string $string * * @return string */ private function canonicalize($string) { return str_replace( ["\r\n", "\r", "\n"], ["\n", "\n", "\r\n"], $string ); } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php 0000777 00000007176 14710744267 0022620 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Base 64 Transfer Encoding in Swift Mailer. * * @author Chris Corbyn */ class Swift_Mime_ContentEncoder_Base64ContentEncoder extends Swift_Encoder_Base64Encoder implements Swift_Mime_ContentEncoder { /** * Encode stream $in to stream $out. * * @param int $firstLineOffset */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { if (0 >= $maxLineLength || 76 < $maxLineLength) { $maxLineLength = 76; } $remainder = 0; $base64ReadBufferRemainderBytes = ''; // To reduce memory usage, the output buffer is streamed to the input buffer like so: // Output Stream => base64encode => wrap line length => Input Stream // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data) // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream. // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the // chunk of bytes read in the next iteration. // When the OutputStream is empty, we must flush any remainder bytes. while (true) { $readBytes = $os->read(8192); $atEOF = (false === $readBytes); if ($atEOF) { $streamTheseBytes = $base64ReadBufferRemainderBytes; } else { $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes; } $base64ReadBufferRemainderBytes = ''; $bytesLength = \strlen($streamTheseBytes); if (0 === $bytesLength) { // no data left to encode break; } // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data // and carry over remainder 1-2 bytes to the next loop iteration if (!$atEOF) { $excessBytes = $bytesLength % 3; if (0 !== $excessBytes) { $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes); $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes); } } $encoded = base64_encode($streamTheseBytes); $encodedTransformed = ''; $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset; while ($thisMaxLineLength < \strlen($encoded)) { $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n"; $firstLineOffset = 0; $encoded = substr($encoded, $thisMaxLineLength); $thisMaxLineLength = $maxLineLength; $remainder = 0; } if (0 < $remainingLength = \strlen($encoded)) { $remainder += $remainingLength; $encodedTransformed .= $encoded; $encoded = null; } $is->write($encodedTransformed); if ($atEOF) { break; } } } /** * Get the name of this encoding scheme. * Returns the string 'base64'. * * @return string */ public function getName() { return 'base64'; } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php 0000777 00000004462 14710744267 0023211 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Proxy for quoted-printable content encoders. * * Switches on the best QP encoder implementation for current charset. * * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com> */ class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder { /** * @var Swift_Mime_ContentEncoder_QpContentEncoder */ private $safeEncoder; /** * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder */ private $nativeEncoder; /** * @var string|null */ private $charset; /** * Constructor. * * @param string|null $charset */ public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset) { $this->safeEncoder = $safeEncoder; $this->nativeEncoder = $nativeEncoder; $this->charset = $charset; } /** * Make a deep copy of object. */ public function __clone() { $this->safeEncoder = clone $this->safeEncoder; $this->nativeEncoder = clone $this->nativeEncoder; } /** * {@inheritdoc} */ public function charsetChanged($charset) { $this->charset = $charset; $this->safeEncoder->charsetChanged($charset); } /** * {@inheritdoc} */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength); } /** * {@inheritdoc} */ public function getName() { return 'quoted-printable'; } /** * {@inheritdoc} */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength); } /** * @return Swift_Mime_ContentEncoder */ private function getEncoder() { return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder; } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NullContentEncoder.php 0000777 00000003466 14710744267 0022504 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles the case where the email body is already encoded and you just need specify the correct * encoding without actually changing the encoding of the body. * * @author Jan Flora <jf@penneo.com> */ class Swift_Mime_ContentEncoder_NullContentEncoder implements Swift_Mime_ContentEncoder { /** * The name of this encoding scheme (probably 7bit or 8bit). * * @var string */ private $name; /** * Creates a new NullContentEncoder with $name (probably 7bit or 8bit). * * @param string $name */ public function __construct($name) { $this->name = $name; } /** * Encode a given string to produce an encoded string. * * @param string $string * @param int $firstLineOffset ignored * @param int $maxLineLength ignored * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { return $string; } /** * Encode stream $in to stream $out. * * @param int $firstLineOffset ignored * @param int $maxLineLength ignored */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { while (false !== ($bytes = $os->read(8192))) { $is->write($bytes); } } /** * Get the name of this encoding scheme. * * @return string */ public function getName() { return $this->name; } /** * Not used. */ public function charsetChanged($charset) { } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php 0000777 00000003023 14710744267 0022310 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles raw Transfer Encoding in Swift Mailer. * * When sending 8-bit content over SMTP, you should use * Swift_Transport_Esmtp_EightBitMimeHandler to enable the 8BITMIME SMTP * extension. * * @author Sebastiaan Stok <s.stok@rollerscapes.net> */ class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder { /** * Encode a given string to produce an encoded string. * * @param string $string * @param int $firstLineOffset ignored * @param int $maxLineLength ignored * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { return $string; } /** * Encode stream $in to stream $out. * * @param int $firstLineOffset ignored * @param int $maxLineLength ignored */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { while (false !== ($bytes = $os->read(8192))) { $is->write($bytes); } } /** * Get the name of this encoding scheme. * * @return string */ public function getName() { return 'raw'; } /** * Not used. */ public function charsetChanged($charset) { } } swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php 0000777 00000006512 14710744267 0023314 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Handles Quoted Printable (QP) Transfer Encoding in Swift Mailer using the PHP core function. * * @author Lars Strojny */ class Swift_Mime_ContentEncoder_NativeQpContentEncoder implements Swift_Mime_ContentEncoder { /** * @var string|null */ private $charset; /** * @param string|null $charset */ public function __construct($charset = null) { $this->charset = $charset ?: 'utf-8'; } /** * Notify this observer that the entity's charset has changed. * * @param string $charset */ public function charsetChanged($charset) { $this->charset = $charset; } /** * Encode $in to $out. * * @param Swift_OutputByteStream $os to read from * @param Swift_InputByteStream $is to write to * @param int $firstLineOffset * @param int $maxLineLength 0 indicates the default length for this encoding * * @throws RuntimeException */ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) { if ('utf-8' !== $this->charset) { throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); } $string = ''; while (false !== $bytes = $os->read(8192)) { $string .= $bytes; } $is->write($this->encodeString($string)); } /** * Get the MIME name of this content encoding scheme. * * @return string */ public function getName() { return 'quoted-printable'; } /** * Encode a given string to produce an encoded string. * * @param string $string * @param int $firstLineOffset if first line needs to be shorter * @param int $maxLineLength 0 indicates the default length for this encoding * * @throws RuntimeException * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { if ('utf-8' !== $this->charset) { throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); } return $this->standardize(quoted_printable_encode($string)); } /** * Make sure CRLF is correct and HT/SPACE are in valid places. * * @param string $string * * @return string */ protected function standardize($string) { // transform CR or LF to CRLF $string = preg_replace('~=0D(?!=0A)|(?<!=0D)=0A~', '=0D=0A', $string); // transform =0D=0A to CRLF $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); switch (\ord(substr($string, -1))) { case 0x09: $string = substr_replace($string, '=09', -1); break; case 0x20: $string = substr_replace($string, '=20', -1); break; } return $string; } } swiftmailer/lib/classes/Swift/CharacterReaderFactory.php 0000777 00000001036 14710744267 0017474 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A factory for creating CharacterReaders. * * @author Chris Corbyn */ interface Swift_CharacterReaderFactory { /** * Returns a CharacterReader suitable for the charset applied. * * @param string $charset * * @return Swift_CharacterReader */ public function getReaderFor($charset); } swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php 0000777 00000003071 14710744267 0020214 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Replaces the sender of a message. * * @author Arjen Brouwer */ class Swift_Plugins_ImpersonatePlugin implements Swift_Events_SendListener { /** * The sender to impersonate. * * @var string */ private $sender; /** * Create a new ImpersonatePlugin to impersonate $sender. * * @param string $sender address */ public function __construct($sender) { $this->sender = $sender; } /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { $message = $evt->getMessage(); $headers = $message->getHeaders(); // save current recipients $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath()); // replace them with the one to send to $message->setReturnPath($this->sender); } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { $message = $evt->getMessage(); // restore original headers $headers = $message->getHeaders(); if ($headers->has('X-Swift-Return-Path')) { $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress()); $headers->removeAll('X-Swift-Return-Path'); } } } swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php 0000777 00000001373 14710744267 0021116 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Allows customization of Messages on-the-fly. * * @author Chris Corbyn */ interface Swift_Plugins_Decorator_Replacements { /** * Return the array of replacements for $address. * * This method is invoked once for every single recipient of a message. * * If no replacements can be found, an empty value (NULL) should be returned * and no replacements will then be made on the message. * * @param string $address * * @return array */ public function getReplacementsFor($address); } swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php 0000777 00000002470 14710744267 0017275 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2011 Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Stores all sent emails for further usage. * * @author Fabien Potencier */ class Swift_Plugins_MessageLogger implements Swift_Events_SendListener { /** * @var Swift_Mime_SimpleMessage[] */ private $messages; public function __construct() { $this->messages = []; } /** * Get the message list. * * @return Swift_Mime_SimpleMessage[] */ public function getMessages() { return $this->messages; } /** * Get the message count. * * @return int count */ public function countMessages() { return \count($this->messages); } /** * Empty the message list. */ public function clear() { $this->messages = []; } /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { $this->messages[] = clone $evt->getMessage(); } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { } } swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Exception.php 0000777 00000001106 14710744267 0020002 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Pop3Exception thrown when an error occurs connecting to a POP3 host. * * @author Chris Corbyn */ class Swift_Plugins_Pop_Pop3Exception extends Swift_IoException { /** * Create a new Pop3Exception with $message. * * @param string $message */ public function __construct($message) { parent::__construct($message); } } swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php 0000777 00000001316 14710744267 0020146 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Pop3Connection interface for connecting and disconnecting to a POP3 host. * * @author Chris Corbyn */ interface Swift_Plugins_Pop_Pop3Connection { /** * Connect to the POP3 host and throw an Exception if it fails. * * @throws Swift_Plugins_Pop_Pop3Exception */ public function connect(); /** * Disconnect from the POP3 host and throw an Exception if it fails. * * @throws Swift_Plugins_Pop_Pop3Exception */ public function disconnect(); } swiftmailer/lib/classes/Swift/Plugins/AntiFloodPlugin.php 0000777 00000005712 14710744267 0017611 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Reduces network flooding when sending large amounts of mail. * * @author Chris Corbyn */ class Swift_Plugins_AntiFloodPlugin implements Swift_Events_SendListener, Swift_Plugins_Sleeper { /** * The number of emails to send before restarting Transport. * * @var int */ private $threshold; /** * The number of seconds to sleep for during a restart. * * @var int */ private $sleep; /** * The internal counter. * * @var int */ private $counter = 0; /** * The Sleeper instance for sleeping. * * @var Swift_Plugins_Sleeper */ private $sleeper; /** * Create a new AntiFloodPlugin with $threshold and $sleep time. * * @param int $threshold * @param int $sleep time * @param Swift_Plugins_Sleeper $sleeper (not needed really) */ public function __construct($threshold = 99, $sleep = 0, Swift_Plugins_Sleeper $sleeper = null) { $this->setThreshold($threshold); $this->setSleepTime($sleep); $this->sleeper = $sleeper; } /** * Set the number of emails to send before restarting. * * @param int $threshold */ public function setThreshold($threshold) { $this->threshold = $threshold; } /** * Get the number of emails to send before restarting. * * @return int */ public function getThreshold() { return $this->threshold; } /** * Set the number of seconds to sleep for during a restart. * * @param int $sleep time */ public function setSleepTime($sleep) { $this->sleep = $sleep; } /** * Get the number of seconds to sleep for during a restart. * * @return int */ public function getSleepTime() { return $this->sleep; } /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { ++$this->counter; if ($this->counter >= $this->threshold) { $transport = $evt->getTransport(); $transport->stop(); if ($this->sleep) { $this->sleep($this->sleep); } $transport->start(); $this->counter = 0; } } /** * Sleep for $seconds. * * @param int $seconds */ public function sleep($seconds) { if (isset($this->sleeper)) { $this->sleeper->sleep($seconds); } else { sleep($seconds); } } } swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php 0000777 00000002162 14710744267 0021163 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A HTML output reporter for the Reporter plugin. * * @author Chris Corbyn */ class Swift_Plugins_Reporters_HtmlReporter implements Swift_Plugins_Reporter { /** * Notifies this ReportNotifier that $address failed or succeeded. * * @param string $address * @param int $result from {@see RESULT_PASS, RESULT_FAIL} */ public function notify(Swift_Mime_SimpleMessage $message, $address, $result) { if (self::RESULT_PASS == $result) { echo '<div style="color: #fff; background: #006600; padding: 2px; margin: 2px;">'.PHP_EOL; echo 'PASS '.$address.PHP_EOL; echo '</div>'.PHP_EOL; flush(); } else { echo '<div style="color: #fff; background: #880000; padding: 2px; margin: 2px;">'.PHP_EOL; echo 'FAIL '.$address.PHP_EOL; echo '</div>'.PHP_EOL; flush(); } } } swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php 0000777 00000002502 14710744267 0021001 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A reporter which "collects" failures for the Reporter plugin. * * @author Chris Corbyn */ class Swift_Plugins_Reporters_HitReporter implements Swift_Plugins_Reporter { /** * The list of failures. * * @var array */ private $failures = []; private $failures_cache = []; /** * Notifies this ReportNotifier that $address failed or succeeded. * * @param string $address * @param int $result from {@link RESULT_PASS, RESULT_FAIL} */ public function notify(Swift_Mime_SimpleMessage $message, $address, $result) { if (self::RESULT_FAIL == $result && !isset($this->failures_cache[$address])) { $this->failures[] = $address; $this->failures_cache[$address] = true; } } /** * Get an array of addresses for which delivery failed. * * @return array */ public function getFailedRecipients() { return $this->failures; } /** * Clear the buffer (empty the list). */ public function clear() { $this->failures = $this->failures_cache = []; } } swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php 0000777 00000002065 14710744267 0020171 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Prints all log messages in real time. * * @author Chris Corbyn */ class Swift_Plugins_Loggers_EchoLogger implements Swift_Plugins_Logger { /** Whether or not HTML should be output */ private $isHtml; /** * Create a new EchoLogger. * * @param bool $isHtml */ public function __construct($isHtml = true) { $this->isHtml = $isHtml; } /** * Add a log entry. * * @param string $entry */ public function add($entry) { if ($this->isHtml) { printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '<br />', PHP_EOL); } else { printf('%s%s', $entry, PHP_EOL); } } /** * Not implemented. */ public function clear() { } /** * Not implemented. */ public function dump() { } } swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php 0000777 00000002337 14710744267 0020373 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Logs to an Array backend. * * @author Chris Corbyn */ class Swift_Plugins_Loggers_ArrayLogger implements Swift_Plugins_Logger { /** * The log contents. * * @var array */ private $log = []; /** * Max size of the log. * * @var int */ private $size = 0; /** * Create a new ArrayLogger with a maximum of $size entries. * * @var int */ public function __construct($size = 50) { $this->size = $size; } /** * Add a log entry. * * @param string $entry */ public function add($entry) { $this->log[] = $entry; while (\count($this->log) > $this->size) { array_shift($this->log); } } /** * Clear the log contents. */ public function clear() { $this->log = []; } /** * Get this log as a string. * * @return string */ public function dump() { return implode(PHP_EOL, $this->log); } } swiftmailer/lib/classes/Swift/Plugins/Reporter.php 0000777 00000001421 14710744267 0016346 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * The Reporter plugin sends pass/fail notification to a Reporter. * * @author Chris Corbyn */ interface Swift_Plugins_Reporter { /** The recipient was accepted for delivery */ const RESULT_PASS = 0x01; /** The recipient could not be accepted */ const RESULT_FAIL = 0x10; /** * Notifies this ReportNotifier that $address failed or succeeded. * * @param string $address * @param int $result from {@link RESULT_PASS, RESULT_FAIL} */ public function notify(Swift_Mime_SimpleMessage $message, $address, $result); } swiftmailer/lib/classes/Swift/Plugins/Logger.php 0000777 00000001146 14710744267 0015767 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Logs events in the Transport system. * * @author Chris Corbyn */ interface Swift_Plugins_Logger { /** * Add a log entry. * * @param string $entry */ public function add($entry); /** * Clear the log contents. */ public function clear(); /** * Get this log as a string. * * @return string */ public function dump(); } swiftmailer/lib/classes/Swift/Plugins/Timer.php 0000777 00000000652 14710744267 0015631 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Provides timestamp data. * * @author Chris Corbyn */ interface Swift_Plugins_Timer { /** * Get the current UNIX timestamp. * * @return int */ public function getTimestamp(); } swiftmailer/lib/classes/Swift/Plugins/ThrottlerPlugin.php 0000777 00000011073 14710744267 0017716 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Throttles the rate at which emails are sent. * * @author Chris Corbyn */ class Swift_Plugins_ThrottlerPlugin extends Swift_Plugins_BandwidthMonitorPlugin implements Swift_Plugins_Sleeper, Swift_Plugins_Timer { /** Flag for throttling in bytes per minute */ const BYTES_PER_MINUTE = 0x01; /** Flag for throttling in emails per second (Amazon SES) */ const MESSAGES_PER_SECOND = 0x11; /** Flag for throttling in emails per minute */ const MESSAGES_PER_MINUTE = 0x10; /** * The Sleeper instance for sleeping. * * @var Swift_Plugins_Sleeper */ private $sleeper; /** * The Timer instance which provides the timestamp. * * @var Swift_Plugins_Timer */ private $timer; /** * The time at which the first email was sent. * * @var int */ private $start; /** * The rate at which messages should be sent. * * @var int */ private $rate; /** * The mode for throttling. * * This is {@link BYTES_PER_MINUTE} or {@link MESSAGES_PER_MINUTE} * * @var int */ private $mode; /** * An internal counter of the number of messages sent. * * @var int */ private $messages = 0; /** * Create a new ThrottlerPlugin. * * @param int $rate * @param int $mode defaults to {@link BYTES_PER_MINUTE} * @param Swift_Plugins_Sleeper $sleeper (only needed in testing) * @param Swift_Plugins_Timer $timer (only needed in testing) */ public function __construct($rate, $mode = self::BYTES_PER_MINUTE, Swift_Plugins_Sleeper $sleeper = null, Swift_Plugins_Timer $timer = null) { $this->rate = $rate; $this->mode = $mode; $this->sleeper = $sleeper; $this->timer = $timer; } /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { $time = $this->getTimestamp(); if (!isset($this->start)) { $this->start = $time; } $duration = $time - $this->start; switch ($this->mode) { case self::BYTES_PER_MINUTE: $sleep = $this->throttleBytesPerMinute($duration); break; case self::MESSAGES_PER_SECOND: $sleep = $this->throttleMessagesPerSecond($duration); break; case self::MESSAGES_PER_MINUTE: $sleep = $this->throttleMessagesPerMinute($duration); break; default: $sleep = 0; break; } if ($sleep > 0) { $this->sleep($sleep); } } /** * Invoked when a Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { parent::sendPerformed($evt); ++$this->messages; } /** * Sleep for $seconds. * * @param int $seconds */ public function sleep($seconds) { if (isset($this->sleeper)) { $this->sleeper->sleep($seconds); } else { sleep($seconds); } } /** * Get the current UNIX timestamp. * * @return int */ public function getTimestamp() { if (isset($this->timer)) { return $this->timer->getTimestamp(); } return time(); } /** * Get a number of seconds to sleep for. * * @param int $timePassed * * @return int */ private function throttleBytesPerMinute($timePassed) { $expectedDuration = $this->getBytesOut() / ($this->rate / 60); return (int) ceil($expectedDuration - $timePassed); } /** * Get a number of seconds to sleep for. * * @param int $timePassed * * @return int */ private function throttleMessagesPerSecond($timePassed) { $expectedDuration = $this->messages / $this->rate; return (int) ceil($expectedDuration - $timePassed); } /** * Get a number of seconds to sleep for. * * @param int $timePassed * * @return int */ private function throttleMessagesPerMinute($timePassed) { $expectedDuration = $this->messages / ($this->rate / 60); return (int) ceil($expectedDuration - $timePassed); } } swiftmailer/lib/classes/Swift/Plugins/PopBeforeSmtpPlugin.php 0000777 00000014057 14710744267 0020461 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Makes sure a connection to a POP3 host has been established prior to connecting to SMTP. * * @author Chris Corbyn */ class Swift_Plugins_PopBeforeSmtpPlugin implements Swift_Events_TransportChangeListener, Swift_Plugins_Pop_Pop3Connection { /** A delegate connection to use (mostly a test hook) */ private $connection; /** Hostname of the POP3 server */ private $host; /** Port number to connect on */ private $port; /** Encryption type to use (if any) */ private $crypto; /** Username to use (if any) */ private $username; /** Password to use (if any) */ private $password; /** Established connection via TCP socket */ private $socket; /** Connect timeout in seconds */ private $timeout = 10; /** SMTP Transport to bind to */ private $transport; /** * Create a new PopBeforeSmtpPlugin for $host and $port. * * @param string $host Hostname or IP. Literal IPv6 addresses should be * wrapped in square brackets. * @param int $port * @param string $crypto as "tls" or "ssl" */ public function __construct($host, $port = 110, $crypto = null) { $this->host = $host; $this->port = $port; $this->crypto = $crypto; } /** * Set a Pop3Connection to delegate to instead of connecting directly. * * @return $this */ public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection) { $this->connection = $connection; return $this; } /** * Bind this plugin to a specific SMTP transport instance. */ public function bindSmtp(Swift_Transport $smtp) { $this->transport = $smtp; } /** * Set the connection timeout in seconds (default 10). * * @param int $timeout * * @return $this */ public function setTimeout($timeout) { $this->timeout = (int) $timeout; return $this; } /** * Set the username to use when connecting (if needed). * * @param string $username * * @return $this */ public function setUsername($username) { $this->username = $username; return $this; } /** * Set the password to use when connecting (if needed). * * @param string $password * * @return $this */ public function setPassword($password) { $this->password = $password; return $this; } /** * Connect to the POP3 host and authenticate. * * @throws Swift_Plugins_Pop_Pop3Exception if connection fails */ public function connect() { if (isset($this->connection)) { $this->connection->connect(); } else { if (!isset($this->socket)) { if (!$socket = fsockopen( $this->getHostString(), $this->port, $errno, $errstr, $this->timeout)) { throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]: %s', $this->host, $errstr)); } $this->socket = $socket; if (false === $greeting = fgets($this->socket)) { throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]', trim($greeting ?? ''))); } $this->assertOk($greeting); if ($this->username) { $this->command(sprintf("USER %s\r\n", $this->username)); $this->command(sprintf("PASS %s\r\n", $this->password)); } } } } /** * Disconnect from the POP3 host. */ public function disconnect() { if (isset($this->connection)) { $this->connection->disconnect(); } else { $this->command("QUIT\r\n"); if (!fclose($this->socket)) { throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 host [%s] connection could not be stopped', $this->host)); } $this->socket = null; } } /** * Invoked just before a Transport is started. */ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) { if (isset($this->transport)) { if ($this->transport !== $evt->getTransport()) { return; } } $this->connect(); $this->disconnect(); } /** * Not used. */ public function transportStarted(Swift_Events_TransportChangeEvent $evt) { } /** * Not used. */ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) { } /** * Not used. */ public function transportStopped(Swift_Events_TransportChangeEvent $evt) { } private function command($command) { if (!fwrite($this->socket, $command)) { throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to write command [%s] to POP3 host', trim($command ?? ''))); } if (false === $response = fgets($this->socket)) { throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to read from POP3 host after command [%s]', trim($command ?? ''))); } $this->assertOk($response); return $response; } private function assertOk($response) { if ('+OK' != substr($response, 0, 3)) { throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 command failed [%s]', trim($response ?? ''))); } } private function getHostString() { $host = $this->host; switch (strtolower($this->crypto ?? '')) { case 'ssl': $host = 'ssl://'.$host; break; case 'tls': $host = 'tls://'.$host; break; } return $host; } } swiftmailer/lib/classes/Swift/Plugins/LoggerPlugin.php 0000777 00000006554 14710744267 0017156 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Does real time logging of Transport level information. * * @author Chris Corbyn */ class Swift_Plugins_LoggerPlugin implements Swift_Events_CommandListener, Swift_Events_ResponseListener, Swift_Events_TransportChangeListener, Swift_Events_TransportExceptionListener, Swift_Plugins_Logger { /** The logger which is delegated to */ private $logger; /** * Create a new LoggerPlugin using $logger. */ public function __construct(Swift_Plugins_Logger $logger) { $this->logger = $logger; } /** * Add a log entry. * * @param string $entry */ public function add($entry) { $this->logger->add($entry); } /** * Clear the log contents. */ public function clear() { $this->logger->clear(); } /** * Get this log as a string. * * @return string */ public function dump() { return $this->logger->dump(); } /** * Invoked immediately following a command being sent. */ public function commandSent(Swift_Events_CommandEvent $evt) { $command = $evt->getCommand(); $this->logger->add(sprintf('>> %s', $command)); } /** * Invoked immediately following a response coming back. */ public function responseReceived(Swift_Events_ResponseEvent $evt) { $response = $evt->getResponse(); $this->logger->add(sprintf('<< %s', $response)); } /** * Invoked just before a Transport is started. */ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) { $transportName = \get_class($evt->getSource()); $this->logger->add(sprintf('++ Starting %s', $transportName)); } /** * Invoked immediately after the Transport is started. */ public function transportStarted(Swift_Events_TransportChangeEvent $evt) { $transportName = \get_class($evt->getSource()); $this->logger->add(sprintf('++ %s started', $transportName)); } /** * Invoked just before a Transport is stopped. */ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) { $transportName = \get_class($evt->getSource()); $this->logger->add(sprintf('++ Stopping %s', $transportName)); } /** * Invoked immediately after the Transport is stopped. */ public function transportStopped(Swift_Events_TransportChangeEvent $evt) { $transportName = \get_class($evt->getSource()); $this->logger->add(sprintf('++ %s stopped', $transportName)); } /** * Invoked as a TransportException is thrown in the Transport system. */ public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt) { $e = $evt->getException(); $message = $e->getMessage(); $code = $e->getCode(); $this->logger->add(sprintf('!! %s (code: %s)', $message, $code)); $message .= PHP_EOL; $message .= 'Log data:'.PHP_EOL; $message .= $this->logger->dump(); $evt->cancelBubble(); throw new Swift_TransportException($message, $code, $e->getPrevious()); } } swiftmailer/lib/classes/Swift/Plugins/Sleeper.php 0000777 00000000657 14710744267 0016155 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Sleeps for a duration of time. * * @author Chris Corbyn */ interface Swift_Plugins_Sleeper { /** * Sleep for $seconds. * * @param int $seconds */ public function sleep($seconds); } swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php 0000777 00000011466 14710744267 0020174 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Redirects all email to a single recipient. * * @author Fabien Potencier */ class Swift_Plugins_RedirectingPlugin implements Swift_Events_SendListener { /** * The recipient who will receive all messages. * * @var mixed */ private $recipient; /** * List of regular expression for recipient whitelisting. * * @var array */ private $whitelist = []; /** * Create a new RedirectingPlugin. * * @param mixed $recipient */ public function __construct($recipient, array $whitelist = []) { $this->recipient = $recipient; $this->whitelist = $whitelist; } /** * Set the recipient of all messages. * * @param mixed $recipient */ public function setRecipient($recipient) { $this->recipient = $recipient; } /** * Get the recipient of all messages. * * @return mixed */ public function getRecipient() { return $this->recipient; } /** * Set a list of regular expressions to whitelist certain recipients. */ public function setWhitelist(array $whitelist) { $this->whitelist = $whitelist; } /** * Get the whitelist. * * @return array */ public function getWhitelist() { return $this->whitelist; } /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { $message = $evt->getMessage(); $headers = $message->getHeaders(); // conditionally save current recipients if ($headers->has('to')) { $headers->addMailboxHeader('X-Swift-To', $message->getTo()); } if ($headers->has('cc')) { $headers->addMailboxHeader('X-Swift-Cc', $message->getCc()); } if ($headers->has('bcc')) { $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc()); } // Filter remaining headers against whitelist $this->filterHeaderSet($headers, 'To'); $this->filterHeaderSet($headers, 'Cc'); $this->filterHeaderSet($headers, 'Bcc'); // Add each hard coded recipient $to = $message->getTo(); if (null === $to) { $to = []; } foreach ((array) $this->recipient as $recipient) { if (!\array_key_exists($recipient, $to)) { $message->addTo($recipient); } } } /** * Filter header set against a whitelist of regular expressions. * * @param string $type */ private function filterHeaderSet(Swift_Mime_SimpleHeaderSet $headerSet, $type) { foreach ($headerSet->getAll($type) as $headers) { $headers->setNameAddresses($this->filterNameAddresses($headers->getNameAddresses())); } } /** * Filtered list of addresses => name pairs. * * @return array */ private function filterNameAddresses(array $recipients) { $filtered = []; foreach ($recipients as $address => $name) { if ($this->isWhitelisted($address)) { $filtered[$address] = $name; } } return $filtered; } /** * Matches address against whitelist of regular expressions. * * @return bool */ protected function isWhitelisted($recipient) { if (\in_array($recipient, (array) $this->recipient)) { return true; } foreach ($this->whitelist as $pattern) { if (preg_match($pattern, $recipient)) { return true; } } return false; } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { $this->restoreMessage($evt->getMessage()); } private function restoreMessage(Swift_Mime_SimpleMessage $message) { // restore original headers $headers = $message->getHeaders(); if ($headers->has('X-Swift-To')) { $message->setTo($headers->get('X-Swift-To')->getNameAddresses()); $headers->removeAll('X-Swift-To'); } else { $message->setTo(null); } if ($headers->has('X-Swift-Cc')) { $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses()); $headers->removeAll('X-Swift-Cc'); } if ($headers->has('X-Swift-Bcc')) { $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses()); $headers->removeAll('X-Swift-Bcc'); } } } swiftmailer/lib/classes/Swift/Plugins/ReporterPlugin.php 0000777 00000003436 14710744267 0017535 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Does real time reporting of pass/fail for each recipient. * * @author Chris Corbyn */ class Swift_Plugins_ReporterPlugin implements Swift_Events_SendListener { /** * The reporter backend which takes notifications. * * @var Swift_Plugins_Reporter */ private $reporter; /** * Create a new ReporterPlugin using $reporter. */ public function __construct(Swift_Plugins_Reporter $reporter) { $this->reporter = $reporter; } /** * Not used. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { $message = $evt->getMessage(); $failures = array_flip($evt->getFailedRecipients()); foreach ((array) $message->getTo() as $address => $null) { $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS)); } foreach ((array) $message->getCc() as $address => $null) { $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS)); } foreach ((array) $message->getBcc() as $address => $null) { $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS)); } } } swiftmailer/lib/classes/Swift/Plugins/DecoratorPlugin.php 0000777 00000015602 14710744267 0017653 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Allows customization of Messages on-the-fly. * * @author Chris Corbyn * @author Fabien Potencier */ class Swift_Plugins_DecoratorPlugin implements Swift_Events_SendListener, Swift_Plugins_Decorator_Replacements { /** The replacement map */ private $replacements; /** The body as it was before replacements */ private $originalBody; /** The original headers of the message, before replacements */ private $originalHeaders = []; /** Bodies of children before they are replaced */ private $originalChildBodies = []; /** The Message that was last replaced */ private $lastMessage; /** * Create a new DecoratorPlugin with $replacements. * * The $replacements can either be an associative array, or an implementation * of {@link Swift_Plugins_Decorator_Replacements}. * * When using an array, it should be of the form: * <code> * $replacements = array( * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") * ) * </code> * * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, * the object should return just the array of replacements for the address * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. * * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements */ public function __construct($replacements) { $this->setReplacements($replacements); } /** * Sets replacements. * * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements * * @see __construct() */ public function setReplacements($replacements) { if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) { $this->replacements = (array) $replacements; } else { $this->replacements = $replacements; } } /** * Invoked immediately before the Message is sent. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { $message = $evt->getMessage(); $this->restoreMessage($message); $to = array_keys($message->getTo()); $address = array_shift($to); if ($replacements = $this->getReplacementsFor($address)) { $body = $message->getBody(); $search = array_keys($replacements); $replace = array_values($replacements); $bodyReplaced = str_replace( $search, $replace, $body ); if ($body != $bodyReplaced) { $this->originalBody = $body; $message->setBody($bodyReplaced); } foreach ($message->getHeaders()->getAll() as $header) { $body = $header->getFieldBodyModel(); $count = 0; if (\is_array($body)) { $bodyReplaced = []; foreach ($body as $key => $value) { $count1 = 0; $count2 = 0; $key = \is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; $value = \is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; $bodyReplaced[$key] = $value; if (!$count && ($count1 || $count2)) { $count = 1; } } } elseif (\is_string($body)) { $bodyReplaced = str_replace($search, $replace, $body, $count); } if ($count) { $this->originalHeaders[$header->getFieldName()] = $body; $header->setFieldBodyModel($bodyReplaced); } } $children = (array) $message->getChildren(); foreach ($children as $child) { list($type) = sscanf($child->getContentType(), '%[^/]/%s'); if ('text' == $type) { $body = $child->getBody(); $bodyReplaced = str_replace( $search, $replace, $body ); if ($body != $bodyReplaced) { $child->setBody($bodyReplaced); $this->originalChildBodies[$child->getId()] = $body; } } } $this->lastMessage = $message; } } /** * Find a map of replacements for the address. * * If this plugin was provided with a delegate instance of * {@link Swift_Plugins_Decorator_Replacements} then the call will be * delegated to it. Otherwise, it will attempt to find the replacements * from the array provided in the constructor. * * If no replacements can be found, an empty value (NULL) is returned. * * @param string $address * * @return array */ public function getReplacementsFor($address) { if ($this->replacements instanceof Swift_Plugins_Decorator_Replacements) { return $this->replacements->getReplacementsFor($address); } return $this->replacements[$address] ?? null; } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { $this->restoreMessage($evt->getMessage()); } /** Restore a changed message back to its original state */ private function restoreMessage(Swift_Mime_SimpleMessage $message) { if ($this->lastMessage === $message) { if (isset($this->originalBody)) { $message->setBody($this->originalBody); $this->originalBody = null; } if (!empty($this->originalHeaders)) { foreach ($message->getHeaders()->getAll() as $header) { if (\array_key_exists($header->getFieldName(), $this->originalHeaders)) { $header->setFieldBodyModel($this->originalHeaders[$header->getFieldName()]); } } $this->originalHeaders = []; } if (!empty($this->originalChildBodies)) { $children = (array) $message->getChildren(); foreach ($children as $child) { $id = $child->getId(); if (\array_key_exists($id, $this->originalChildBodies)) { $child->setBody($this->originalChildBodies[$id]); } } $this->originalChildBodies = []; } $this->lastMessage = null; } } } swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php 0000777 00000006446 14710744267 0021213 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Reduces network flooding when sending large amounts of mail. * * @author Chris Corbyn */ class Swift_Plugins_BandwidthMonitorPlugin implements Swift_Events_SendListener, Swift_Events_CommandListener, Swift_Events_ResponseListener, Swift_InputByteStream { /** * The outgoing traffic counter. * * @var int */ private $out = 0; /** * The incoming traffic counter. * * @var int */ private $in = 0; /** Bound byte streams */ private $mirrors = []; /** * Not used. */ public function beforeSendPerformed(Swift_Events_SendEvent $evt) { } /** * Invoked immediately after the Message is sent. */ public function sendPerformed(Swift_Events_SendEvent $evt) { $message = $evt->getMessage(); $message->toByteStream($this); } /** * Invoked immediately following a command being sent. */ public function commandSent(Swift_Events_CommandEvent $evt) { $command = $evt->getCommand(); $this->out += \strlen($command); } /** * Invoked immediately following a response coming back. */ public function responseReceived(Swift_Events_ResponseEvent $evt) { $response = $evt->getResponse(); $this->in += \strlen($response); } /** * Called when a message is sent so that the outgoing counter can be increased. * * @param string $bytes */ public function write($bytes) { $this->out += \strlen($bytes); foreach ($this->mirrors as $stream) { $stream->write($bytes); } } /** * Not used. */ public function commit() { } /** * Attach $is to this stream. * * The stream acts as an observer, receiving all data that is written. * All {@link write()} and {@link flushBuffers()} operations will be mirrored. */ public function bind(Swift_InputByteStream $is) { $this->mirrors[] = $is; } /** * Remove an already bound stream. * * If $is is not bound, no errors will be raised. * If the stream currently has any buffered data it will be written to $is * before unbinding occurs. */ public function unbind(Swift_InputByteStream $is) { foreach ($this->mirrors as $k => $stream) { if ($is === $stream) { unset($this->mirrors[$k]); } } } /** * Not used. */ public function flushBuffers() { foreach ($this->mirrors as $stream) { $stream->flushBuffers(); } } /** * Get the total number of bytes sent to the server. * * @return int */ public function getBytesOut() { return $this->out; } /** * Get the total number of bytes received from the server. * * @return int */ public function getBytesIn() { return $this->in; } /** * Reset the internal counters to zero. */ public function reset() { $this->out = 0; $this->in = 0; } } swiftmailer/lib/classes/Swift/ConfigurableSpool.php 0000777 00000002522 14710744267 0016543 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Base class for Spools (implements time and message limits). * * @author Fabien Potencier */ abstract class Swift_ConfigurableSpool implements Swift_Spool { /** The maximum number of messages to send per flush */ private $message_limit; /** The time limit per flush */ private $time_limit; /** * Sets the maximum number of messages to send per flush. * * @param int $limit */ public function setMessageLimit($limit) { $this->message_limit = (int) $limit; } /** * Gets the maximum number of messages to send per flush. * * @return int The limit */ public function getMessageLimit() { return $this->message_limit; } /** * Sets the time limit (in seconds) per flush. * * @param int $limit The limit */ public function setTimeLimit($limit) { $this->time_limit = (int) $limit; } /** * Gets the time limit (in seconds) per flush. * * @return int The limit */ public function getTimeLimit() { return $this->time_limit; } } swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php 0000777 00000002056 14710744267 0020454 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Writes data to a KeyCache using a stream. * * @author Chris Corbyn */ interface Swift_KeyCache_KeyCacheInputStream extends Swift_InputByteStream { /** * Set the KeyCache to wrap. */ public function setKeyCache(Swift_KeyCache $keyCache); /** * Set the nsKey which will be written to. * * @param string $nsKey */ public function setNsKey($nsKey); /** * Set the itemKey which will be written to. * * @param string $itemKey */ public function setItemKey($itemKey); /** * Specify a stream to write through for each write(). */ public function setWriteThroughStream(Swift_InputByteStream $is); /** * Any implementation should be cloneable, allowing the clone to access a * separate $nsKey and $itemKey. */ public function __clone(); } swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php 0000777 00000017561 14710744267 0017102 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A KeyCache which streams to and from disk. * * @author Chris Corbyn */ class Swift_KeyCache_DiskKeyCache implements Swift_KeyCache { /** Signal to place pointer at start of file */ const POSITION_START = 0; /** Signal to place pointer at end of file */ const POSITION_END = 1; /** Signal to leave pointer in whatever position it currently is */ const POSITION_CURRENT = 2; /** * An InputStream for cloning. * * @var Swift_KeyCache_KeyCacheInputStream */ private $stream; /** * A path to write to. * * @var string */ private $path; /** * Stored keys. * * @var array */ private $keys = []; /** * Create a new DiskKeyCache with the given $stream for cloning to make * InputByteStreams, and the given $path to save to. * * @param string $path to save to */ public function __construct(Swift_KeyCache_KeyCacheInputStream $stream, $path) { $this->stream = $stream; $this->path = $path; } /** * Set a string into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param string $string * @param int $mode * * @throws Swift_IoException */ public function setString($nsKey, $itemKey, $string, $mode) { $this->prepareCache($nsKey); switch ($mode) { case self::MODE_WRITE: $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); break; case self::MODE_APPEND: $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_END); break; default: throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); break; } fwrite($fp, $string); $this->freeHandle($nsKey, $itemKey); } /** * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param int $mode * * @throws Swift_IoException */ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) { $this->prepareCache($nsKey); switch ($mode) { case self::MODE_WRITE: $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); break; case self::MODE_APPEND: $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_END); break; default: throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); break; } while (false !== $bytes = $os->read(8192)) { fwrite($fp, $bytes); } $this->freeHandle($nsKey, $itemKey); } /** * Provides a ByteStream which when written to, writes data to $itemKey. * * NOTE: The stream will always write in append mode. * * @param string $nsKey * @param string $itemKey * * @return Swift_InputByteStream */ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) { $is = clone $this->stream; $is->setKeyCache($this); $is->setNsKey($nsKey); $is->setItemKey($itemKey); if (isset($writeThrough)) { $is->setWriteThroughStream($writeThrough); } return $is; } /** * Get data back out of the cache as a string. * * @param string $nsKey * @param string $itemKey * * @throws Swift_IoException * * @return string */ public function getString($nsKey, $itemKey) { $this->prepareCache($nsKey); if ($this->hasKey($nsKey, $itemKey)) { $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); $str = ''; while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { $str .= $bytes; } $this->freeHandle($nsKey, $itemKey); return $str; } } /** * Get data back out of the cache as a ByteStream. * * @param string $nsKey * @param string $itemKey * @param Swift_InputByteStream $is to write the data to */ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) { if ($this->hasKey($nsKey, $itemKey)) { $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { $is->write($bytes); } $this->freeHandle($nsKey, $itemKey); } } /** * Check if the given $itemKey exists in the namespace $nsKey. * * @param string $nsKey * @param string $itemKey * * @return bool */ public function hasKey($nsKey, $itemKey) { return is_file($this->path.'/'.$nsKey.'/'.$itemKey); } /** * Clear data for $itemKey in the namespace $nsKey if it exists. * * @param string $nsKey * @param string $itemKey */ public function clearKey($nsKey, $itemKey) { if ($this->hasKey($nsKey, $itemKey)) { $this->freeHandle($nsKey, $itemKey); unlink($this->path.'/'.$nsKey.'/'.$itemKey); } } /** * Clear all data in the namespace $nsKey if it exists. * * @param string $nsKey */ public function clearAll($nsKey) { if (\array_key_exists($nsKey, $this->keys)) { foreach ($this->keys[$nsKey] as $itemKey => $null) { $this->clearKey($nsKey, $itemKey); } if (is_dir($this->path.'/'.$nsKey)) { rmdir($this->path.'/'.$nsKey); } unset($this->keys[$nsKey]); } } /** * Initialize the namespace of $nsKey if needed. * * @param string $nsKey */ private function prepareCache($nsKey) { $cacheDir = $this->path.'/'.$nsKey; if (!is_dir($cacheDir)) { if (!mkdir($cacheDir)) { throw new Swift_IoException('Failed to create cache directory '.$cacheDir); } $this->keys[$nsKey] = []; } } /** * Get a file handle on the cache item. * * @param string $nsKey * @param string $itemKey * @param int $position * * @return resource */ private function getHandle($nsKey, $itemKey, $position) { if (!isset($this->keys[$nsKey][$itemKey])) { $openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b'; $fp = fopen($this->path.'/'.$nsKey.'/'.$itemKey, $openMode); $this->keys[$nsKey][$itemKey] = $fp; } if (self::POSITION_START == $position) { fseek($this->keys[$nsKey][$itemKey], 0, SEEK_SET); } elseif (self::POSITION_END == $position) { fseek($this->keys[$nsKey][$itemKey], 0, SEEK_END); } return $this->keys[$nsKey][$itemKey]; } private function freeHandle($nsKey, $itemKey) { $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_CURRENT); fclose($fp); $this->keys[$nsKey][$itemKey] = null; } /** * Destructor. */ public function __destruct() { foreach ($this->keys as $nsKey => $null) { $this->clearAll($nsKey); } } public function __wakeup() { $this->keys = []; } } swiftmailer/lib/classes/Swift/KeyCache/ArrayKeyCache.php 0000777 00000012171 14710744267 0017256 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A basic KeyCache backed by an array. * * @author Chris Corbyn */ class Swift_KeyCache_ArrayKeyCache implements Swift_KeyCache { /** * Cache contents. * * @var array */ private $contents = []; /** * An InputStream for cloning. * * @var Swift_KeyCache_KeyCacheInputStream */ private $stream; /** * Create a new ArrayKeyCache with the given $stream for cloning to make * InputByteStreams. */ public function __construct(Swift_KeyCache_KeyCacheInputStream $stream) { $this->stream = $stream; } /** * Set a string into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param string $string * @param int $mode */ public function setString($nsKey, $itemKey, $string, $mode) { $this->prepareCache($nsKey); switch ($mode) { case self::MODE_WRITE: $this->contents[$nsKey][$itemKey] = $string; break; case self::MODE_APPEND: if (!$this->hasKey($nsKey, $itemKey)) { $this->contents[$nsKey][$itemKey] = ''; } $this->contents[$nsKey][$itemKey] .= $string; break; default: throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); } } /** * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param int $mode */ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) { $this->prepareCache($nsKey); switch ($mode) { case self::MODE_WRITE: $this->clearKey($nsKey, $itemKey); // no break case self::MODE_APPEND: if (!$this->hasKey($nsKey, $itemKey)) { $this->contents[$nsKey][$itemKey] = ''; } while (false !== $bytes = $os->read(8192)) { $this->contents[$nsKey][$itemKey] .= $bytes; } break; default: throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey); } } /** * Provides a ByteStream which when written to, writes data to $itemKey. * * NOTE: The stream will always write in append mode. * * @param string $nsKey * @param string $itemKey * * @return Swift_InputByteStream */ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) { $is = clone $this->stream; $is->setKeyCache($this); $is->setNsKey($nsKey); $is->setItemKey($itemKey); if (isset($writeThrough)) { $is->setWriteThroughStream($writeThrough); } return $is; } /** * Get data back out of the cache as a string. * * @param string $nsKey * @param string $itemKey * * @return string */ public function getString($nsKey, $itemKey) { $this->prepareCache($nsKey); if ($this->hasKey($nsKey, $itemKey)) { return $this->contents[$nsKey][$itemKey]; } } /** * Get data back out of the cache as a ByteStream. * * @param string $nsKey * @param string $itemKey * @param Swift_InputByteStream $is to write the data to */ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) { $this->prepareCache($nsKey); $is->write($this->getString($nsKey, $itemKey)); } /** * Check if the given $itemKey exists in the namespace $nsKey. * * @param string $nsKey * @param string $itemKey * * @return bool */ public function hasKey($nsKey, $itemKey) { $this->prepareCache($nsKey); return \array_key_exists($itemKey, $this->contents[$nsKey]); } /** * Clear data for $itemKey in the namespace $nsKey if it exists. * * @param string $nsKey * @param string $itemKey */ public function clearKey($nsKey, $itemKey) { unset($this->contents[$nsKey][$itemKey]); } /** * Clear all data in the namespace $nsKey if it exists. * * @param string $nsKey */ public function clearAll($nsKey) { unset($this->contents[$nsKey]); } /** * Initialize the namespace of $nsKey if needed. * * @param string $nsKey */ private function prepareCache($nsKey) { if (!\array_key_exists($nsKey, $this->contents)) { $this->contents[$nsKey] = []; } } } swiftmailer/lib/classes/Swift/KeyCache/NullKeyCache.php 0000777 00000005032 14710744267 0017110 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A null KeyCache that does not cache at all. * * @author Chris Corbyn */ class Swift_KeyCache_NullKeyCache implements Swift_KeyCache { /** * Set a string into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param string $string * @param int $mode */ public function setString($nsKey, $itemKey, $string, $mode) { } /** * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. * * @see MODE_WRITE, MODE_APPEND * * @param string $nsKey * @param string $itemKey * @param int $mode */ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) { } /** * Provides a ByteStream which when written to, writes data to $itemKey. * * NOTE: The stream will always write in append mode. * * @param string $nsKey * @param string $itemKey * * @return Swift_InputByteStream */ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) { } /** * Get data back out of the cache as a string. * * @param string $nsKey * @param string $itemKey * * @return string */ public function getString($nsKey, $itemKey) { } /** * Get data back out of the cache as a ByteStream. * * @param string $nsKey * @param string $itemKey * @param Swift_InputByteStream $is to write the data to */ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) { } /** * Check if the given $itemKey exists in the namespace $nsKey. * * @param string $nsKey * @param string $itemKey * * @return bool */ public function hasKey($nsKey, $itemKey) { return false; } /** * Clear data for $itemKey in the namespace $nsKey if it exists. * * @param string $nsKey * @param string $itemKey */ public function clearKey($nsKey, $itemKey) { } /** * Clear all data in the namespace $nsKey if it exists. * * @param string $nsKey */ public function clearAll($nsKey) { } } swiftmailer/lib/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php 0000777 00000005162 14710744267 0021627 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Writes data to a KeyCache using a stream. * * @author Chris Corbyn */ class Swift_KeyCache_SimpleKeyCacheInputStream implements Swift_KeyCache_KeyCacheInputStream { /** The KeyCache being written to */ private $keyCache; /** The nsKey of the KeyCache being written to */ private $nsKey; /** The itemKey of the KeyCache being written to */ private $itemKey; /** A stream to write through on each write() */ private $writeThrough = null; /** * Set the KeyCache to wrap. */ public function setKeyCache(Swift_KeyCache $keyCache) { $this->keyCache = $keyCache; } /** * Specify a stream to write through for each write(). */ public function setWriteThroughStream(Swift_InputByteStream $is) { $this->writeThrough = $is; } /** * Writes $bytes to the end of the stream. * * @param string $bytes * @param Swift_InputByteStream $is optional */ public function write($bytes, Swift_InputByteStream $is = null) { $this->keyCache->setString( $this->nsKey, $this->itemKey, $bytes, Swift_KeyCache::MODE_APPEND ); if (isset($is)) { $is->write($bytes); } if (isset($this->writeThrough)) { $this->writeThrough->write($bytes); } } /** * Not used. */ public function commit() { } /** * Not used. */ public function bind(Swift_InputByteStream $is) { } /** * Not used. */ public function unbind(Swift_InputByteStream $is) { } /** * Flush the contents of the stream (empty it) and set the internal pointer * to the beginning. */ public function flushBuffers() { $this->keyCache->clearKey($this->nsKey, $this->itemKey); } /** * Set the nsKey which will be written to. * * @param string $nsKey */ public function setNsKey($nsKey) { $this->nsKey = $nsKey; } /** * Set the itemKey which will be written to. * * @param string $itemKey */ public function setItemKey($itemKey) { $this->itemKey = $itemKey; } /** * Any implementation should be cloneable, allowing the clone to access a * separate $nsKey and $itemKey. */ public function __clone() { $this->writeThrough = null; } } swiftmailer/lib/classes/Swift/Encoder.php 0000777 00000001336 14710744267 0014507 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Interface for all Encoder schemes. * * @author Chris Corbyn */ interface Swift_Encoder extends Swift_Mime_CharsetObserver { /** * Encode a given string to produce an encoded string. * * @param string $string * @param int $firstLineOffset if first line needs to be shorter * @param int $maxLineLength - 0 indicates the default length for this encoding * * @return string */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0); } swiftmailer/lib/classes/Swift/FailoverTransport.php 0000777 00000001541 14710744267 0016612 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Contains a list of redundant Transports so when one fails, the next is used. * * @author Chris Corbyn */ class Swift_FailoverTransport extends Swift_Transport_FailoverTransport { /** * Creates a new FailoverTransport with $transports. * * @param Swift_Transport[] $transports */ public function __construct($transports = []) { \call_user_func_array( [$this, 'Swift_Transport_FailoverTransport::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('transport.failover') ); $this->setTransports($transports); } } swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php 0000777 00000014671 14710744267 0021543 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A CharacterStream implementation which stores characters in an internal array. * * @author Xavier De Cock <xdecock@gmail.com> */ class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream { /** * The char reader (lazy-loaded) for the current charset. * * @var Swift_CharacterReader */ private $charReader; /** * A factory for creating CharacterReader instances. * * @var Swift_CharacterReaderFactory */ private $charReaderFactory; /** * The character set this stream is using. * * @var string */ private $charset; /** * The data's stored as-is. * * @var string */ private $datas = ''; /** * Number of bytes in the stream. * * @var int */ private $datasSize = 0; /** * Map. * * @var mixed */ private $map; /** * Map Type. * * @var int */ private $mapType = 0; /** * Number of characters in the stream. * * @var int */ private $charCount = 0; /** * Position in the stream. * * @var int */ private $currentPos = 0; /** * Constructor. * * @param string $charset */ public function __construct(Swift_CharacterReaderFactory $factory, $charset) { $this->setCharacterReaderFactory($factory); $this->setCharacterSet($charset); } /* -- Changing parameters of the stream -- */ /** * Set the character set used in this CharacterStream. * * @param string $charset */ public function setCharacterSet($charset) { $this->charset = $charset; $this->charReader = null; $this->mapType = 0; } /** * Set the CharacterReaderFactory for multi charset support. */ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) { $this->charReaderFactory = $factory; } /** * @see Swift_CharacterStream::flushContents() */ public function flushContents() { $this->datas = null; $this->map = null; $this->charCount = 0; $this->currentPos = 0; $this->datasSize = 0; } /** * @see Swift_CharacterStream::importByteStream() */ public function importByteStream(Swift_OutputByteStream $os) { $this->flushContents(); $blocks = 512; $os->setReadPointer(0); while (false !== ($read = $os->read($blocks))) { $this->write($read); } } /** * @see Swift_CharacterStream::importString() * * @param string $string */ public function importString($string) { $this->flushContents(); $this->write($string); } /** * @see Swift_CharacterStream::read() * * @param int $length * * @return string */ public function read($length) { if ($this->currentPos >= $this->charCount) { return false; } $ret = false; $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; switch ($this->mapType) { case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: $len = $length * $this->map; $ret = substr($this->datas, $this->currentPos * $this->map, $len); $this->currentPos += $length; break; case Swift_CharacterReader::MAP_TYPE_INVALID: $ret = ''; for (; $this->currentPos < $length; ++$this->currentPos) { if (isset($this->map[$this->currentPos])) { $ret .= '?'; } else { $ret .= $this->datas[$this->currentPos]; } } break; case Swift_CharacterReader::MAP_TYPE_POSITIONS: $end = $this->currentPos + $length; $end = $end > $this->charCount ? $this->charCount : $end; $ret = ''; $start = 0; if ($this->currentPos > 0) { $start = $this->map['p'][$this->currentPos - 1]; } $to = $start; for (; $this->currentPos < $end; ++$this->currentPos) { if (isset($this->map['i'][$this->currentPos])) { $ret .= substr($this->datas, $start, $to - $start).'?'; $start = $this->map['p'][$this->currentPos]; } else { $to = $this->map['p'][$this->currentPos]; } } $ret .= substr($this->datas, $start, $to - $start); break; } return $ret; } /** * @see Swift_CharacterStream::readBytes() * * @param int $length * * @return int[] */ public function readBytes($length) { $read = $this->read($length); if (false !== $read) { $ret = array_map('ord', str_split($read, 1)); return $ret; } return false; } /** * @see Swift_CharacterStream::setPointer() * * @param int $charOffset */ public function setPointer($charOffset) { if ($this->charCount < $charOffset) { $charOffset = $this->charCount; } $this->currentPos = $charOffset; } /** * @see Swift_CharacterStream::write() * * @param string $chars */ public function write($chars) { if (!isset($this->charReader)) { $this->charReader = $this->charReaderFactory->getReaderFor( $this->charset); $this->map = []; $this->mapType = $this->charReader->getMapType(); } $ignored = ''; $this->datas .= $chars; $this->charCount += $this->charReader->getCharPositions(substr($this->datas, $this->datasSize), $this->datasSize, $this->map, $ignored); if (false !== $ignored) { $this->datasSize = \strlen($this->datas) - \strlen($ignored); } else { $this->datasSize = \strlen($this->datas); } } } swiftmailer/lib/classes/Swift/CharacterStream/ArrayCharacterStream.php 0000777 00000020132 14710744267 0022242 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * A CharacterStream implementation which stores characters in an internal array. * * @author Chris Corbyn */ class Swift_CharacterStream_ArrayCharacterStream implements Swift_CharacterStream { /** A map of byte values and their respective characters */ private static $charMap; /** A map of characters and their derivative byte values */ private static $byteMap; /** The char reader (lazy-loaded) for the current charset */ private $charReader; /** A factory for creating CharacterReader instances */ private $charReaderFactory; /** The character set this stream is using */ private $charset; /** Array of characters */ private $array = []; /** Size of the array of character */ private $array_size = []; /** The current character offset in the stream */ private $offset = 0; /** * Create a new CharacterStream with the given $chars, if set. * * @param Swift_CharacterReaderFactory $factory for loading validators * @param string $charset used in the stream */ public function __construct(Swift_CharacterReaderFactory $factory, $charset) { self::initializeMaps(); $this->setCharacterReaderFactory($factory); $this->setCharacterSet($charset); } /** * Set the character set used in this CharacterStream. * * @param string $charset */ public function setCharacterSet($charset) { $this->charset = $charset; $this->charReader = null; } /** * Set the CharacterReaderFactory for multi charset support. */ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) { $this->charReaderFactory = $factory; } /** * Overwrite this character stream using the byte sequence in the byte stream. * * @param Swift_OutputByteStream $os output stream to read from */ public function importByteStream(Swift_OutputByteStream $os) { if (!isset($this->charReader)) { $this->charReader = $this->charReaderFactory ->getReaderFor($this->charset); } $startLength = $this->charReader->getInitialByteSize(); while (false !== $bytes = $os->read($startLength)) { $c = []; for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) { $c[] = self::$byteMap[$bytes[$i]]; } $size = \count($c); $need = $this->charReader ->validateByteSequence($c, $size); if ($need > 0 && false !== $bytes = $os->read($need)) { for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) { $c[] = self::$byteMap[$bytes[$i]]; } } $this->array[] = $c; ++$this->array_size; } } /** * Import a string a bytes into this CharacterStream, overwriting any existing * data in the stream. * * @param string $string */ public function importString($string) { $this->flushContents(); $this->write($string); } /** * Read $length characters from the stream and move the internal pointer * $length further into the stream. * * @param int $length * * @return string */ public function read($length) { if ($this->offset == $this->array_size) { return false; } // Don't use array slice $arrays = []; $end = $length + $this->offset; for ($i = $this->offset; $i < $end; ++$i) { if (!isset($this->array[$i])) { break; } $arrays[] = $this->array[$i]; } $this->offset += $i - $this->offset; // Limit function calls $chars = false; foreach ($arrays as $array) { $chars .= implode('', array_map('chr', $array)); } return $chars; } /** * Read $length characters from the stream and return a 1-dimensional array * containing there octet values. * * @param int $length * * @return int[] */ public function readBytes($length) { if ($this->offset == $this->array_size) { return false; } $arrays = []; $end = $length + $this->offset; for ($i = $this->offset; $i < $end; ++$i) { if (!isset($this->array[$i])) { break; } $arrays[] = $this->array[$i]; } $this->offset += ($i - $this->offset); // Limit function calls return array_merge(...$arrays); } /** * Write $chars to the end of the stream. * * @param string $chars */ public function write($chars) { if (!isset($this->charReader)) { $this->charReader = $this->charReaderFactory->getReaderFor( $this->charset); } $startLength = $this->charReader->getInitialByteSize(); $fp = fopen('php://memory', 'w+b'); fwrite($fp, $chars); unset($chars); fseek($fp, 0, SEEK_SET); $buffer = [0]; $buf_pos = 1; $buf_len = 1; $has_datas = true; do { $bytes = []; // Buffer Filing if ($buf_len - $buf_pos < $startLength) { $buf = array_splice($buffer, $buf_pos); $new = $this->reloadBuffer($fp, 100); if ($new) { $buffer = array_merge($buf, $new); $buf_len = \count($buffer); $buf_pos = 0; } else { $has_datas = false; } } if ($buf_len - $buf_pos > 0) { $size = 0; for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) { ++$size; $bytes[] = $buffer[$buf_pos++]; } $need = $this->charReader->validateByteSequence( $bytes, $size); if ($need > 0) { if ($buf_len - $buf_pos < $need) { $new = $this->reloadBuffer($fp, $need); if ($new) { $buffer = array_merge($buffer, $new); $buf_len = \count($buffer); } } for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) { $bytes[] = $buffer[$buf_pos++]; } } $this->array[] = $bytes; ++$this->array_size; } } while ($has_datas); fclose($fp); } /** * Move the internal pointer to $charOffset in the stream. * * @param int $charOffset */ public function setPointer($charOffset) { if ($charOffset > $this->array_size) { $charOffset = $this->array_size; } elseif ($charOffset < 0) { $charOffset = 0; } $this->offset = $charOffset; } /** * Empty the stream and reset the internal pointer. */ public function flushContents() { $this->offset = 0; $this->array = []; $this->array_size = 0; } private function reloadBuffer($fp, $len) { if (!feof($fp) && false !== ($bytes = fread($fp, $len))) { $buf = []; for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) { $buf[] = self::$byteMap[$bytes[$i]]; } return $buf; } return false; } private static function initializeMaps() { if (!isset(self::$charMap)) { self::$charMap = []; for ($byte = 0; $byte < 256; ++$byte) { self::$charMap[$byte] = \chr($byte); } self::$byteMap = array_flip(self::$charMap); } } } swiftmailer/lib/classes/Swift/Filterable.php 0000777 00000001162 14710744267 0015176 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Allows StreamFilters to operate on a stream. * * @author Chris Corbyn */ interface Swift_Filterable { /** * Add a new StreamFilter, referenced by $key. * * @param string $key */ public function addFilter(Swift_StreamFilter $filter, $key); /** * Remove an existing filter using $key. * * @param string $key */ public function removeFilter($key); } swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php 0000777 00000001045 14710744267 0020062 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Creates StreamFilters. * * @author Chris Corbyn */ interface Swift_ReplacementFilterFactory { /** * Create a filter to replace $search with $replace. * * @param mixed $search * @param mixed $replace * * @return Swift_StreamFilter */ public function createFilter($search, $replace); } swiftmailer/lib/classes/Swift/FileSpool.php 0000777 00000012764 14710744267 0015033 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Stores Messages on the filesystem. * * @author Fabien Potencier * @author Xavier De Cock <xdecock@gmail.com> */ class Swift_FileSpool extends Swift_ConfigurableSpool { /** The spool directory */ private $path; /** * File WriteRetry Limit. * * @var int */ private $retryLimit = 10; /** * Create a new FileSpool. * * @param string $path * * @throws Swift_IoException */ public function __construct($path) { $this->path = $path; if (!file_exists($this->path)) { if (!mkdir($this->path, 0777, true)) { throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->path)); } } } /** * Tests if this Spool mechanism has started. * * @return bool */ public function isStarted() { return true; } /** * Starts this Spool mechanism. */ public function start() { } /** * Stops this Spool mechanism. */ public function stop() { } /** * Allow to manage the enqueuing retry limit. * * Default, is ten and allows over 64^20 different fileNames * * @param int $limit */ public function setRetryLimit($limit) { $this->retryLimit = $limit; } /** * Queues a message. * * @param Swift_Mime_SimpleMessage $message The message to store * * @throws Swift_IoException * * @return bool */ public function queueMessage(Swift_Mime_SimpleMessage $message) { $ser = serialize($message); $fileName = $this->path.'/'.$this->getRandomString(10); for ($i = 0; $i < $this->retryLimit; ++$i) { /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */ $fp = @fopen($fileName.'.message', 'xb'); if (false !== $fp) { if (false === fwrite($fp, $ser)) { return false; } return fclose($fp); } else { /* The file already exists, we try a longer fileName */ $fileName .= $this->getRandomString(1); } } throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->path)); } /** * Execute a recovery if for any reason a process is sending for too long. * * @param int $timeout in second Defaults is for very slow smtp responses */ public function recover($timeout = 900) { foreach (new DirectoryIterator($this->path) as $file) { $file = $file->getRealPath(); if ('.message.sending' == substr($file, -16)) { $lockedtime = filectime($file); if ((time() - $lockedtime) > $timeout) { rename($file, substr($file, 0, -8)); } } } } /** * Sends messages using the given transport instance. * * @param Swift_Transport $transport A transport instance * @param string[] $failedRecipients An array of failures by-reference * * @return int The number of sent e-mail's */ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) { $directoryIterator = new DirectoryIterator($this->path); /* Start the transport only if there are queued files to send */ if (!$transport->isStarted()) { foreach ($directoryIterator as $file) { if ('.message' == substr($file->getRealPath(), -8)) { $transport->start(); break; } } } $failedRecipients = (array) $failedRecipients; $count = 0; $time = time(); foreach ($directoryIterator as $file) { $file = $file->getRealPath(); if ('.message' != substr($file, -8)) { continue; } /* We try a rename, it's an atomic operation, and avoid locking the file */ if (rename($file, $file.'.sending')) { $message = unserialize(file_get_contents($file.'.sending')); $count += $transport->send($message, $failedRecipients); unlink($file.'.sending'); } else { /* This message has just been catched by another process */ continue; } if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) { break; } if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) { break; } } return $count; } /** * Returns a random string needed to generate a fileName for the queue. * * @param int $count * * @return string */ protected function getRandomString($count) { // This string MUST stay FS safe, avoid special chars $base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; $ret = ''; $strlen = \strlen($base); for ($i = 0; $i < $count; ++$i) { $ret .= $base[random_int(0, $strlen - 1)]; } return $ret; } } swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php 0000777 00000007667 14710744267 0023155 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Provides the base functionality for an InputStream supporting filters. * * @author Chris Corbyn */ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_InputByteStream, Swift_Filterable { /** * Write sequence. */ protected $sequence = 0; /** * StreamFilters. * * @var Swift_StreamFilter[] */ private $filters = []; /** * A buffer for writing. */ private $writeBuffer = ''; /** * Bound streams. * * @var Swift_InputByteStream[] */ private $mirrors = []; /** * Commit the given bytes to the storage medium immediately. * * @param string $bytes */ abstract protected function doCommit($bytes); /** * Flush any buffers/content with immediate effect. */ abstract protected function flush(); /** * Add a StreamFilter to this InputByteStream. * * @param string $key */ public function addFilter(Swift_StreamFilter $filter, $key) { $this->filters[$key] = $filter; } /** * Remove an already present StreamFilter based on its $key. * * @param string $key */ public function removeFilter($key) { unset($this->filters[$key]); } /** * Writes $bytes to the end of the stream. * * @param string $bytes * * @throws Swift_IoException * * @return int */ public function write($bytes) { $this->writeBuffer .= $bytes; foreach ($this->filters as $filter) { if ($filter->shouldBuffer($this->writeBuffer)) { return; } } $this->doWrite($this->writeBuffer); return ++$this->sequence; } /** * For any bytes that are currently buffered inside the stream, force them * off the buffer. * * @throws Swift_IoException */ public function commit() { $this->doWrite($this->writeBuffer); } /** * Attach $is to this stream. * * The stream acts as an observer, receiving all data that is written. * All {@link write()} and {@link flushBuffers()} operations will be mirrored. */ public function bind(Swift_InputByteStream $is) { $this->mirrors[] = $is; } /** * Remove an already bound stream. * * If $is is not bound, no errors will be raised. * If the stream currently has any buffered data it will be written to $is * before unbinding occurs. */ public function unbind(Swift_InputByteStream $is) { foreach ($this->mirrors as $k => $stream) { if ($is === $stream) { if ('' !== $this->writeBuffer) { $stream->write($this->writeBuffer); } unset($this->mirrors[$k]); } } } /** * Flush the contents of the stream (empty it) and set the internal pointer * to the beginning. * * @throws Swift_IoException */ public function flushBuffers() { if ('' !== $this->writeBuffer) { $this->doWrite($this->writeBuffer); } $this->flush(); foreach ($this->mirrors as $stream) { $stream->flushBuffers(); } } /** Run $bytes through all filters */ private function filter($bytes) { foreach ($this->filters as $filter) { $bytes = $filter->filter($bytes); } return $bytes; } /** Just write the bytes to the stream */ private function doWrite($bytes) { $this->doCommit($this->filter($bytes)); foreach ($this->mirrors as $stream) { $stream->write($bytes); } $this->writeBuffer = ''; } } swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php 0000777 00000010062 14710744267 0020261 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Allows reading and writing of bytes to and from an array. * * @author Chris Corbyn */ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_OutputByteStream { /** * The internal stack of bytes. * * @var string[] */ private $array = []; /** * The size of the stack. * * @var int */ private $arraySize = 0; /** * The internal pointer offset. * * @var int */ private $offset = 0; /** * Bound streams. * * @var Swift_InputByteStream[] */ private $mirrors = []; /** * Create a new ArrayByteStream. * * If $stack is given the stream will be populated with the bytes it contains. * * @param mixed $stack of bytes in string or array form, optional */ public function __construct($stack = null) { if (\is_array($stack)) { $this->array = $stack; $this->arraySize = \count($stack); } elseif (\is_string($stack)) { $this->write($stack); } else { $this->array = []; } } /** * Reads $length bytes from the stream into a string and moves the pointer * through the stream by $length. * * If less bytes exist than are requested the * remaining bytes are given instead. If no bytes are remaining at all, boolean * false is returned. * * @param int $length * * @return string */ public function read($length) { if ($this->offset == $this->arraySize) { return false; } // Don't use array slice $end = $length + $this->offset; $end = $this->arraySize < $end ? $this->arraySize : $end; $ret = ''; for (; $this->offset < $end; ++$this->offset) { $ret .= $this->array[$this->offset]; } return $ret; } /** * Writes $bytes to the end of the stream. * * @param string $bytes */ public function write($bytes) { $to_add = str_split($bytes); foreach ($to_add as $value) { $this->array[] = $value; } $this->arraySize = \count($this->array); foreach ($this->mirrors as $stream) { $stream->write($bytes); } } /** * Not used. */ public function commit() { } /** * Attach $is to this stream. * * The stream acts as an observer, receiving all data that is written. * All {@link write()} and {@link flushBuffers()} operations will be mirrored. */ public function bind(Swift_InputByteStream $is) { $this->mirrors[] = $is; } /** * Remove an already bound stream. * * If $is is not bound, no errors will be raised. * If the stream currently has any buffered data it will be written to $is * before unbinding occurs. */ public function unbind(Swift_InputByteStream $is) { foreach ($this->mirrors as $k => $stream) { if ($is === $stream) { unset($this->mirrors[$k]); } } } /** * Move the internal read pointer to $byteOffset in the stream. * * @param int $byteOffset * * @return bool */ public function setReadPointer($byteOffset) { if ($byteOffset > $this->arraySize) { $byteOffset = $this->arraySize; } elseif ($byteOffset < 0) { $byteOffset = 0; } $this->offset = $byteOffset; } /** * Flush the contents of the stream (empty it) and set the internal pointer * to the beginning. */ public function flushBuffers() { $this->offset = 0; $this->array = []; $this->arraySize = 0; foreach ($this->mirrors as $stream) { $stream->flushBuffers(); } } } swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php 0000777 00000002325 14710744267 0021770 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * @author Romain-Geissler */ class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream { public function __construct() { $filePath = tempnam(sys_get_temp_dir(), 'FileByteStream'); if (false === $filePath) { throw new Swift_IoException('Failed to retrieve temporary file name.'); } parent::__construct($filePath, true); } public function getContent() { if (false === ($content = file_get_contents($this->getPath()))) { throw new Swift_IoException('Failed to get temporary file content.'); } return $content; } public function __destruct() { if (file_exists($this->getPath())) { @unlink($this->getPath()); } } public function __sleep() { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } public function __wakeup() { throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); } } swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php 0000777 00000013641 14710744267 0020070 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Allows reading and writing of bytes to and from a file. * * @author Chris Corbyn */ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream implements Swift_FileStream { /** The internal pointer offset */ private $offset = 0; /** The path to the file */ private $path; /** The mode this file is opened in for writing */ private $mode; /** A lazy-loaded resource handle for reading the file */ private $reader; /** A lazy-loaded resource handle for writing the file */ private $writer; /** If stream is seekable true/false, or null if not known */ private $seekable = null; /** * Create a new FileByteStream for $path. * * @param string $path * @param bool $writable if true */ public function __construct($path, $writable = false) { if (empty($path)) { throw new Swift_IoException('The path cannot be empty'); } $this->path = $path; $this->mode = $writable ? 'w+b' : 'rb'; } /** * Get the complete path to the file. * * @return string */ public function getPath() { return $this->path; } /** * Reads $length bytes from the stream into a string and moves the pointer * through the stream by $length. * * If less bytes exist than are requested the * remaining bytes are given instead. If no bytes are remaining at all, boolean * false is returned. * * @param int $length * * @return string|bool * * @throws Swift_IoException */ public function read($length) { $fp = $this->getReadHandle(); if (!feof($fp)) { $bytes = fread($fp, $length); $this->offset = ftell($fp); // If we read one byte after reaching the end of the file // feof() will return false and an empty string is returned if ((false === $bytes || '' === $bytes) && feof($fp)) { $this->resetReadHandle(); return false; } return $bytes; } $this->resetReadHandle(); return false; } /** * Move the internal read pointer to $byteOffset in the stream. * * @param int $byteOffset * * @return bool */ public function setReadPointer($byteOffset) { if (isset($this->reader)) { $this->seekReadStreamToPosition($byteOffset); } $this->offset = $byteOffset; } /** Just write the bytes to the file */ protected function doCommit($bytes) { fwrite($this->getWriteHandle(), $bytes); $this->resetReadHandle(); } /** Not used */ protected function flush() { } /** Get the resource for reading */ private function getReadHandle() { if (!isset($this->reader)) { $pointer = @fopen($this->path, 'rb'); if (!$pointer) { throw new Swift_IoException('Unable to open file for reading ['.$this->path.']'); } $this->reader = $pointer; if (0 != $this->offset) { $this->getReadStreamSeekableStatus(); $this->seekReadStreamToPosition($this->offset); } } return $this->reader; } /** Get the resource for writing */ private function getWriteHandle() { if (!isset($this->writer)) { if (!$this->writer = fopen($this->path, $this->mode)) { throw new Swift_IoException('Unable to open file for writing ['.$this->path.']'); } } return $this->writer; } /** Force a reload of the resource for reading */ private function resetReadHandle() { if (isset($this->reader)) { fclose($this->reader); $this->reader = null; } } /** Check if ReadOnly Stream is seekable */ private function getReadStreamSeekableStatus() { $metas = stream_get_meta_data($this->reader); $this->seekable = $metas['seekable']; } /** Streams in a readOnly stream ensuring copy if needed */ private function seekReadStreamToPosition($offset) { if (null === $this->seekable) { $this->getReadStreamSeekableStatus(); } if (false === $this->seekable) { $currentPos = ftell($this->reader); if ($currentPos < $offset) { $toDiscard = $offset - $currentPos; fread($this->reader, $toDiscard); return; } $this->copyReadStream(); } fseek($this->reader, $offset, SEEK_SET); } /** Copy a readOnly Stream to ensure seekability */ private function copyReadStream() { if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) { /* We have opened a php:// Stream Should work without problem */ } elseif (\function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) { /* We have opened a tmpfile */ } else { throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available'); } $currentPos = ftell($this->reader); fclose($this->reader); $source = fopen($this->path, 'rb'); if (!$source) { throw new Swift_IoException('Unable to open file for copying ['.$this->path.']'); } fseek($tmpFile, 0, SEEK_SET); while (!feof($source)) { fwrite($tmpFile, fread($source, 4096)); } fseek($tmpFile, $currentPos, SEEK_SET); fclose($source); $this->reader = $tmpFile; } } swiftmailer/lib/classes/Swift/AddressEncoder.php 0000777 00000001123 14710744267 0016007 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2018 Christian Schmidt * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Email address encoder. * * @author Christian Schmidt */ interface Swift_AddressEncoder { /** * Encodes an email address. * * @throws Swift_AddressEncoderException if the email cannot be represented in * the encoding implemented by this class */ public function encodeString(string $address): string; } swiftmailer/lib/classes/Swift/InputByteStream.php 0000777 00000003653 14710744267 0016233 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * An abstract means of writing data. * * Classes implementing this interface may use a subsystem which requires less * memory than working with large strings of data. * * @author Chris Corbyn */ interface Swift_InputByteStream { /** * Writes $bytes to the end of the stream. * * Writing may not happen immediately if the stream chooses to buffer. If * you want to write these bytes with immediate effect, call {@link commit()} * after calling write(). * * This method returns the sequence ID of the write (i.e. 1 for first, 2 for * second, etc etc). * * @param string $bytes * * @throws Swift_IoException * * @return int */ public function write($bytes); /** * For any bytes that are currently buffered inside the stream, force them * off the buffer. * * @throws Swift_IoException */ public function commit(); /** * Attach $is to this stream. * * The stream acts as an observer, receiving all data that is written. * All {@link write()} and {@link flushBuffers()} operations will be mirrored. * * @param Swift_InputByteStream $is */ public function bind(self $is); /** * Remove an already bound stream. * * If $is is not bound, no errors will be raised. * If the stream currently has any buffered data it will be written to $is * before unbinding occurs. * * @param Swift_InputByteStream $is */ public function unbind(self $is); /** * Flush the contents of the stream (empty it) and set the internal pointer * to the beginning. * * @throws Swift_IoException */ public function flushBuffers(); } swiftmailer/lib/classes/Swift/IoException.php 0000777 00000001135 14710744267 0015353 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * I/O Exception class. * * @author Chris Corbyn */ class Swift_IoException extends Swift_SwiftException { /** * Create a new IoException with $message. * * @param string $message * @param int $code */ public function __construct($message, $code = 0, Exception $previous = null) { parent::__construct($message, $code, $previous); } } swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php 0000777 00000020115 14710744267 0020114 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Analyzes UTF-8 characters. * * @author Chris Corbyn * @author Xavier De Cock <xdecock@gmail.com> */ class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader { /** Pre-computed for optimization */ private static $length_map = [ // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x4N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6N 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x7N 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x8N 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x9N 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xAN 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xBN 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN ]; private static $s_length_map = [ "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, ]; /** * Returns the complete character map. * * @param string $string * @param int $startOffset * @param array $currentMap * @param mixed $ignoredChars * * @return int */ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) { if (!isset($currentMap['i']) || !isset($currentMap['p'])) { $currentMap['p'] = $currentMap['i'] = []; } $strlen = \strlen($string); $charPos = \count($currentMap['p']); $foundChars = 0; $invalid = false; for ($i = 0; $i < $strlen; ++$i) { $char = $string[$i]; $size = self::$s_length_map[$char]; if (0 == $size) { /* char is invalid, we must wait for a resync */ $invalid = true; continue; } else { if (true === $invalid) { /* We mark the chars as invalid and start a new char */ $currentMap['p'][$charPos + $foundChars] = $startOffset + $i; $currentMap['i'][$charPos + $foundChars] = true; ++$foundChars; $invalid = false; } if (($i + $size) > $strlen) { $ignoredChars = substr($string, $i); break; } for ($j = 1; $j < $size; ++$j) { $char = $string[$i + $j]; if ($char > "\x7F" && $char < "\xC0") { // Valid - continue parsing } else { /* char is invalid, we must wait for a resync */ $invalid = true; continue 2; } } /* Ok we got a complete char here */ $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size; $i += $j - 1; ++$foundChars; } } return $foundChars; } /** * Returns mapType. * * @return int mapType */ public function getMapType() { return self::MAP_TYPE_POSITIONS; } /** * Returns an integer which specifies how many more bytes to read. * * A positive integer indicates the number of more bytes to fetch before invoking * this method again. * A value of zero means this is already a valid character. * A value of -1 means this cannot possibly be a valid character. * * @param string $bytes * @param int $size * * @return int */ public function validateByteSequence($bytes, $size) { if ($size < 1) { return -1; } $needed = self::$length_map[$bytes[0]] - $size; return $needed > -1 ? $needed : -1; } /** * Returns the number of bytes which should be read to start each character. * * @return int */ public function getInitialByteSize() { return 1; } } swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php 0000777 00000004475 14710744267 0022635 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Provides fixed-width byte sizes for reading fixed-width character sets. * * @author Chris Corbyn * @author Xavier De Cock <xdecock@gmail.com> */ class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader { /** * The number of bytes in a single character. * * @var int */ private $width; /** * Creates a new GenericFixedWidthReader using $width bytes per character. * * @param int $width */ public function __construct($width) { $this->width = $width; } /** * Returns the complete character map. * * @param string $string * @param int $startOffset * @param array $currentMap * @param mixed $ignoredChars * * @return int */ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) { $strlen = \strlen($string); // % and / are CPU intensive, so, maybe find a better way $ignored = $strlen % $this->width; $ignoredChars = $ignored ? substr($string, -$ignored) : ''; $currentMap = $this->width; return ($strlen - $ignored) / $this->width; } /** * Returns the mapType. * * @return int */ public function getMapType() { return self::MAP_TYPE_FIXED_LEN; } /** * Returns an integer which specifies how many more bytes to read. * * A positive integer indicates the number of more bytes to fetch before invoking * this method again. * * A value of zero means this is already a valid character. * A value of -1 means this cannot possibly be a valid character. * * @param string $bytes * @param int $size * * @return int */ public function validateByteSequence($bytes, $size) { $needed = $this->width - $size; return $needed > -1 ? $needed : -1; } /** * Returns the number of bytes which should be read to start each character. * * @return int */ public function getInitialByteSize() { return $this->width; } } swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php 0000777 00000003672 14710744267 0020637 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Analyzes US-ASCII characters. * * @author Chris Corbyn */ class Swift_CharacterReader_UsAsciiReader implements Swift_CharacterReader { /** * Returns the complete character map. * * @param string $string * @param int $startOffset * @param array $currentMap * @param string $ignoredChars * * @return int */ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) { $strlen = \strlen($string); $ignoredChars = ''; for ($i = 0; $i < $strlen; ++$i) { if ($string[$i] > "\x07F") { // Invalid char $currentMap[$i + $startOffset] = $string[$i]; } } return $strlen; } /** * Returns mapType. * * @return int mapType */ public function getMapType() { return self::MAP_TYPE_INVALID; } /** * Returns an integer which specifies how many more bytes to read. * * A positive integer indicates the number of more bytes to fetch before invoking * this method again. * A value of zero means this is already a valid character. * A value of -1 means this cannot possibly be a valid character. * * @param string $bytes * @param int $size * * @return int */ public function validateByteSequence($bytes, $size) { $byte = reset($bytes); if (1 == \count($bytes) && $byte >= 0x00 && $byte <= 0x7F) { return 0; } return -1; } /** * Returns the number of bytes which should be read to start each character. * * @return int */ public function getInitialByteSize() { return 1; } } swiftmailer/lib/classes/Swift/Preferences.php 0000777 00000004261 14710744267 0015371 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Changes some global preference settings in Swift Mailer. * * @author Chris Corbyn */ class Swift_Preferences { /** Singleton instance */ private static $instance = null; /** Constructor not to be used */ private function __construct() { } /** * Gets the instance of Preferences. * * @return self */ public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Set the default charset used. * * @param string $charset * * @return $this */ public function setCharset($charset) { Swift_DependencyContainer::getInstance()->register('properties.charset')->asValue($charset); return $this; } /** * Set the directory where temporary files can be saved. * * @param string $dir * * @return $this */ public function setTempDir($dir) { Swift_DependencyContainer::getInstance()->register('tempdir')->asValue($dir); return $this; } /** * Set the type of cache to use (i.e. "disk" or "array"). * * @param string $type * * @return $this */ public function setCacheType($type) { Swift_DependencyContainer::getInstance()->register('cache')->asAliasOf(sprintf('cache.%s', $type)); return $this; } /** * Set the QuotedPrintable dot escaper preference. * * @param bool $dotEscape * * @return $this */ public function setQPDotEscape($dotEscape) { $dotEscape = !empty($dotEscape); Swift_DependencyContainer::getInstance() ->register('mime.qpcontentencoder') ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') ->withDependencies(['mime.charstream', 'mime.bytecanonicalizer']) ->addConstructorValue($dotEscape); return $this; } } swiftmailer/lib/classes/Swift/SmtpTransport.php 0000777 00000003273 14710744267 0015772 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Sends Messages over SMTP with ESMTP support. * * @author Chris Corbyn * * @method Swift_SmtpTransport setUsername(string $username) Set the username to authenticate with. * @method string getUsername() Get the username to authenticate with. * @method Swift_SmtpTransport setPassword(string $password) Set the password to authenticate with. * @method string getPassword() Get the password to authenticate with. * @method Swift_SmtpTransport setAuthMode(string $mode) Set the auth mode to use to authenticate. * @method string getAuthMode() Get the auth mode to use to authenticate. */ class Swift_SmtpTransport extends Swift_Transport_EsmtpTransport { /** * @param string $host * @param int $port * @param string|null $encryption SMTP encryption mode: * - null for plain SMTP (no encryption), * - 'tls' for SMTP with STARTTLS (best effort encryption), * - 'ssl' for SMTPS = SMTP over TLS (always encrypted). */ public function __construct($host = 'localhost', $port = 25, $encryption = null) { \call_user_func_array( [$this, 'Swift_Transport_EsmtpTransport::__construct'], Swift_DependencyContainer::getInstance() ->createDependenciesFor('transport.smtp') ); $this->setHost($host); $this->setPort($port); $this->setEncryption($encryption); } } swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php 0000777 00000001350 14710744267 0017771 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Provides an abstract way of specifying recipients for batch sending. * * @author Chris Corbyn */ interface Swift_Mailer_RecipientIterator { /** * Returns true only if there are more recipients to send to. * * @return bool */ public function hasNext(); /** * Returns an array where the keys are the addresses of recipients and the * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL). * * @return array */ public function nextRecipient(); } swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php 0000777 00000002214 14710744267 0020770 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * Wraps a standard PHP array in an iterator. * * @author Chris Corbyn */ class Swift_Mailer_ArrayRecipientIterator implements Swift_Mailer_RecipientIterator { /** * The list of recipients. * * @var array */ private $recipients = []; /** * Create a new ArrayRecipientIterator from $recipients. */ public function __construct(array $recipients) { $this->recipients = $recipients; } /** * Returns true only if there are more recipients to send to. * * @return bool */ public function hasNext() { return !empty($this->recipients); } /** * Returns an array where the keys are the addresses of recipients and the * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL). * * @return array */ public function nextRecipient() { return array_splice($this->recipients, 0, 1); } } swiftmailer/lib/classes/Swift.php 0000777 00000003670 14710744267 0013133 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ /** * General utility class in Swift Mailer, not to be instantiated. * * @author Chris Corbyn */ abstract class Swift { const VERSION = '6.3.0'; public static $initialized = false; public static $inits = []; /** * Registers an initializer callable that will be called the first time * a SwiftMailer class is autoloaded. * * This enables you to tweak the default configuration in a lazy way. * * @param mixed $callable A valid PHP callable that will be called when autoloading the first Swift class */ public static function init($callable) { self::$inits[] = $callable; } /** * Internal autoloader for spl_autoload_register(). * * @param string $class */ public static function autoload($class) { // Don't interfere with other autoloaders if (0 !== strpos($class, 'Swift_')) { return; } $path = __DIR__.'/'.str_replace('_', '/', $class).'.php'; if (!file_exists($path)) { return; } require $path; if (self::$inits && !self::$initialized) { self::$initialized = true; foreach (self::$inits as $init) { \call_user_func($init); } } } /** * Configure autoloading using Swift Mailer. * * This is designed to play nicely with other autoloaders. * * @param mixed $callable A valid PHP callable that will be called when autoloading the first Swift class */ public static function registerAutoload($callable = null) { if (null !== $callable) { self::$inits[] = $callable; } spl_autoload_register(['Swift', 'autoload']); } } swiftmailer/lib/mime_types.php 0000777 00000120032 14710744267 0012545 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. * * autogenerated using https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types * and https://raw.github.com/minad/mimemagic/master/script/freedesktop.org.xml */ /* * List of MIME type automatically detected in Swift Mailer. */ // You may add or take away what you like (lowercase required) $swift_mime_types = [ '3dml' => 'text/vnd.in3d.3dml', '3ds' => 'image/x-3ds', '3g2' => 'video/3gpp2', '3gp' => 'video/3gpp', '7z' => 'application/x-7z-compressed', 'aab' => 'application/x-authorware-bin', 'aac' => 'audio/x-aac', 'aam' => 'application/x-authorware-map', 'aas' => 'application/x-authorware-seg', 'abw' => 'application/x-abiword', 'ac' => 'application/pkix-attr-cert', 'acc' => 'application/vnd.americandynamics.acc', 'ace' => 'application/x-ace-compressed', 'acu' => 'application/vnd.acucobol', 'acutc' => 'application/vnd.acucorp', 'adp' => 'audio/adpcm', 'aep' => 'application/vnd.audiograph', 'afm' => 'application/x-font-type1', 'afp' => 'application/vnd.ibm.modcap', 'ahead' => 'application/vnd.ahead.space', 'ai' => 'application/postscript', 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'air' => 'application/vnd.adobe.air-application-installer-package+zip', 'ait' => 'application/vnd.dvb.ait', 'ami' => 'application/vnd.amiga.ami', 'apk' => 'application/vnd.android.package-archive', 'appcache' => 'text/cache-manifest', 'apr' => 'application/vnd.lotus-approach', 'aps' => 'application/postscript', 'arc' => 'application/x-freearc', 'asc' => 'application/pgp-signature', 'asf' => 'video/x-ms-asf', 'asm' => 'text/x-asm', 'aso' => 'application/vnd.accpac.simply.aso', 'asx' => 'video/x-ms-asf', 'atc' => 'application/vnd.acucorp', 'atom' => 'application/atom+xml', 'atomcat' => 'application/atomcat+xml', 'atomsvc' => 'application/atomsvc+xml', 'atx' => 'application/vnd.antix.game-component', 'au' => 'audio/basic', 'avi' => 'video/x-msvideo', 'aw' => 'application/applixware', 'azf' => 'application/vnd.airzip.filesecure.azf', 'azs' => 'application/vnd.airzip.filesecure.azs', 'azw' => 'application/vnd.amazon.ebook', 'bat' => 'application/x-msdownload', 'bcpio' => 'application/x-bcpio', 'bdf' => 'application/x-font-bdf', 'bdm' => 'application/vnd.syncml.dm+wbxml', 'bed' => 'application/vnd.realvnc.bed', 'bh2' => 'application/vnd.fujitsu.oasysprs', 'bin' => 'application/octet-stream', 'blb' => 'application/x-blorb', 'blorb' => 'application/x-blorb', 'bmi' => 'application/vnd.bmi', 'bmp' => 'image/bmp', 'book' => 'application/vnd.framemaker', 'box' => 'application/vnd.previewsystems.box', 'boz' => 'application/x-bzip2', 'bpk' => 'application/octet-stream', 'btif' => 'image/prs.btif', 'bz' => 'application/x-bzip', 'bz2' => 'application/x-bzip2', 'c' => 'text/x-c', 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', 'c4d' => 'application/vnd.clonk.c4group', 'c4f' => 'application/vnd.clonk.c4group', 'c4g' => 'application/vnd.clonk.c4group', 'c4p' => 'application/vnd.clonk.c4group', 'c4u' => 'application/vnd.clonk.c4group', 'cab' => 'application/vnd.ms-cab-compressed', 'caf' => 'audio/x-caf', 'cap' => 'application/vnd.tcpdump.pcap', 'car' => 'application/vnd.curl.car', 'cat' => 'application/vnd.ms-pki.seccat', 'cb7' => 'application/x-cbr', 'cba' => 'application/x-cbr', 'cbr' => 'application/x-cbr', 'cbt' => 'application/x-cbr', 'cbz' => 'application/x-cbr', 'cc' => 'text/x-c', 'cct' => 'application/x-director', 'ccxml' => 'application/ccxml+xml', 'cdbcmsg' => 'application/vnd.contact.cmsg', 'cdf' => 'application/x-netcdf', 'cdkey' => 'application/vnd.mediastation.cdkey', 'cdmia' => 'application/cdmi-capability', 'cdmic' => 'application/cdmi-container', 'cdmid' => 'application/cdmi-domain', 'cdmio' => 'application/cdmi-object', 'cdmiq' => 'application/cdmi-queue', 'cdx' => 'chemical/x-cdx', 'cdxml' => 'application/vnd.chemdraw+xml', 'cdy' => 'application/vnd.cinderella', 'cer' => 'application/pkix-cert', 'cfs' => 'application/x-cfs-compressed', 'cgm' => 'image/cgm', 'chat' => 'application/x-chat', 'chm' => 'application/vnd.ms-htmlhelp', 'chrt' => 'application/vnd.kde.kchart', 'cif' => 'chemical/x-cif', 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', 'cil' => 'application/vnd.ms-artgalry', 'cla' => 'application/vnd.claymore', 'class' => 'application/java-vm', 'clkk' => 'application/vnd.crick.clicker.keyboard', 'clkp' => 'application/vnd.crick.clicker.palette', 'clkt' => 'application/vnd.crick.clicker.template', 'clkw' => 'application/vnd.crick.clicker.wordbank', 'clkx' => 'application/vnd.crick.clicker', 'clp' => 'application/x-msclip', 'cmc' => 'application/vnd.cosmocaller', 'cmdf' => 'chemical/x-cmdf', 'cml' => 'chemical/x-cml', 'cmp' => 'application/vnd.yellowriver-custom-menu', 'cmx' => 'image/x-cmx', 'cod' => 'application/vnd.rim.cod', 'com' => 'application/x-msdownload', 'conf' => 'text/plain', 'cpio' => 'application/x-cpio', 'cpp' => 'text/x-c', 'cpt' => 'application/mac-compactpro', 'crd' => 'application/x-mscardfile', 'crl' => 'application/pkix-crl', 'crt' => 'application/x-x509-ca-cert', 'csh' => 'application/x-csh', 'csml' => 'chemical/x-csml', 'csp' => 'application/vnd.commonspace', 'css' => 'text/css', 'cst' => 'application/x-director', 'csv' => 'text/csv', 'cu' => 'application/cu-seeme', 'curl' => 'text/vnd.curl', 'cww' => 'application/prs.cww', 'cxt' => 'application/x-director', 'cxx' => 'text/x-c', 'dae' => 'model/vnd.collada+xml', 'daf' => 'application/vnd.mobius.daf', 'dart' => 'application/vnd.dart', 'dataless' => 'application/vnd.fdsn.seed', 'davmount' => 'application/davmount+xml', 'dbk' => 'application/docbook+xml', 'dcr' => 'application/x-director', 'dcurl' => 'text/vnd.curl.dcurl', 'dd2' => 'application/vnd.oma.dd2+xml', 'ddd' => 'application/vnd.fujixerox.ddd', 'deb' => 'application/x-debian-package', 'def' => 'text/plain', 'deploy' => 'application/octet-stream', 'der' => 'application/x-x509-ca-cert', 'dfac' => 'application/vnd.dreamfactory', 'dgc' => 'application/x-dgc-compressed', 'dic' => 'text/x-c', 'dir' => 'application/x-director', 'dis' => 'application/vnd.mobius.dis', 'dist' => 'application/octet-stream', 'distz' => 'application/octet-stream', 'djv' => 'image/vnd.djvu', 'djvu' => 'image/vnd.djvu', 'dll' => 'application/x-msdownload', 'dmg' => 'application/x-apple-diskimage', 'dmp' => 'application/vnd.tcpdump.pcap', 'dms' => 'application/octet-stream', 'dna' => 'application/vnd.dna', 'doc' => 'application/msword', 'docm' => 'application/vnd.ms-word.document.macroenabled.12', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'dot' => 'application/msword', 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dp' => 'application/vnd.osgi.dp', 'dpg' => 'application/vnd.dpgraph', 'dra' => 'audio/vnd.dra', 'dsc' => 'text/prs.lines.tag', 'dssc' => 'application/dssc+der', 'dtb' => 'application/x-dtbook+xml', 'dtd' => 'application/xml-dtd', 'dts' => 'audio/vnd.dts', 'dtshd' => 'audio/vnd.dts.hd', 'dump' => 'application/octet-stream', 'dvb' => 'video/vnd.dvb.file', 'dvi' => 'application/x-dvi', 'dwf' => 'model/vnd.dwf', 'dwg' => 'image/vnd.dwg', 'dxf' => 'image/vnd.dxf', 'dxp' => 'application/vnd.spotfire.dxp', 'dxr' => 'application/x-director', 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', 'ecma' => 'application/ecmascript', 'edm' => 'application/vnd.novadigm.edm', 'edx' => 'application/vnd.novadigm.edx', 'efif' => 'application/vnd.picsel', 'ei6' => 'application/vnd.pg.osasli', 'elc' => 'application/octet-stream', 'emf' => 'application/x-msmetafile', 'eml' => 'message/rfc822', 'emma' => 'application/emma+xml', 'emz' => 'application/x-msmetafile', 'eol' => 'audio/vnd.digital-winds', 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', 'epub' => 'application/epub+zip', 'es3' => 'application/vnd.eszigno3+xml', 'esa' => 'application/vnd.osgi.subsystem', 'esf' => 'application/vnd.epson.esf', 'et3' => 'application/vnd.eszigno3+xml', 'etx' => 'text/x-setext', 'eva' => 'application/x-eva', 'evy' => 'application/x-envoy', 'exe' => 'application/x-msdownload', 'exi' => 'application/exi', 'ext' => 'application/vnd.novadigm.ext', 'ez' => 'application/andrew-inset', 'ez2' => 'application/vnd.ezpix-album', 'ez3' => 'application/vnd.ezpix-package', 'f' => 'text/x-fortran', 'f4v' => 'video/x-f4v', 'f77' => 'text/x-fortran', 'f90' => 'text/x-fortran', 'fbs' => 'image/vnd.fastbidsheet', 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', 'fcs' => 'application/vnd.isac.fcs', 'fdf' => 'application/vnd.fdf', 'fe_launch' => 'application/vnd.denovo.fcselayout-link', 'fg5' => 'application/vnd.fujitsu.oasysgp', 'fgd' => 'application/x-director', 'fh' => 'image/x-freehand', 'fh4' => 'image/x-freehand', 'fh5' => 'image/x-freehand', 'fh7' => 'image/x-freehand', 'fhc' => 'image/x-freehand', 'fig' => 'application/x-xfig', 'flac' => 'audio/x-flac', 'fli' => 'video/x-fli', 'flo' => 'application/vnd.micrografx.flo', 'flv' => 'video/x-flv', 'flw' => 'application/vnd.kde.kivio', 'flx' => 'text/vnd.fmi.flexstor', 'fly' => 'text/vnd.fly', 'fm' => 'application/vnd.framemaker', 'fnc' => 'application/vnd.frogans.fnc', 'for' => 'text/x-fortran', 'fpx' => 'image/vnd.fpx', 'frame' => 'application/vnd.framemaker', 'fsc' => 'application/vnd.fsc.weblaunch', 'fst' => 'image/vnd.fst', 'ftc' => 'application/vnd.fluxtime.clip', 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', 'fvt' => 'video/vnd.fvt', 'fxp' => 'application/vnd.adobe.fxp', 'fxpl' => 'application/vnd.adobe.fxp', 'fzs' => 'application/vnd.fuzzysheet', 'g2w' => 'application/vnd.geoplan', 'g3' => 'image/g3fax', 'g3w' => 'application/vnd.geospace', 'gac' => 'application/vnd.groove-account', 'gam' => 'application/x-tads', 'gbr' => 'application/rpki-ghostbusters', 'gca' => 'application/x-gca-compressed', 'gdl' => 'model/vnd.gdl', 'geo' => 'application/vnd.dynageo', 'gex' => 'application/vnd.geometry-explorer', 'ggb' => 'application/vnd.geogebra.file', 'ggt' => 'application/vnd.geogebra.tool', 'ghf' => 'application/vnd.groove-help', 'gif' => 'image/gif', 'gim' => 'application/vnd.groove-identity-message', 'gml' => 'application/gml+xml', 'gmx' => 'application/vnd.gmx', 'gnumeric' => 'application/x-gnumeric', 'gph' => 'application/vnd.flographit', 'gpx' => 'application/gpx+xml', 'gqf' => 'application/vnd.grafeq', 'gqs' => 'application/vnd.grafeq', 'gram' => 'application/srgs', 'gramps' => 'application/x-gramps-xml', 'gre' => 'application/vnd.geometry-explorer', 'grv' => 'application/vnd.groove-injector', 'grxml' => 'application/srgs+xml', 'gsf' => 'application/x-font-ghostscript', 'gtar' => 'application/x-gtar', 'gtm' => 'application/vnd.groove-tool-message', 'gtw' => 'model/vnd.gtw', 'gv' => 'text/vnd.graphviz', 'gxf' => 'application/gxf', 'gxt' => 'application/vnd.geonext', 'gz' => 'application/x-gzip', 'h' => 'text/x-c', 'h261' => 'video/h261', 'h263' => 'video/h263', 'h264' => 'video/h264', 'hal' => 'application/vnd.hal+xml', 'hbci' => 'application/vnd.hbci', 'hdf' => 'application/x-hdf', 'hh' => 'text/x-c', 'hlp' => 'application/winhlp', 'hpgl' => 'application/vnd.hp-hpgl', 'hpid' => 'application/vnd.hp-hpid', 'hps' => 'application/vnd.hp-hps', 'hqx' => 'application/mac-binhex40', 'htke' => 'application/vnd.kenameaapp', 'htm' => 'text/html', 'html' => 'text/html', 'hvd' => 'application/vnd.yamaha.hv-dic', 'hvp' => 'application/vnd.yamaha.hv-voice', 'hvs' => 'application/vnd.yamaha.hv-script', 'i2g' => 'application/vnd.intergeo', 'icc' => 'application/vnd.iccprofile', 'ice' => 'x-conference/x-cooltalk', 'icm' => 'application/vnd.iccprofile', 'ico' => 'image/x-icon', 'ics' => 'text/calendar', 'ief' => 'image/ief', 'ifb' => 'text/calendar', 'ifm' => 'application/vnd.shana.informed.formdata', 'iges' => 'model/iges', 'igl' => 'application/vnd.igloader', 'igm' => 'application/vnd.insors.igm', 'igs' => 'model/iges', 'igx' => 'application/vnd.micrografx.igx', 'iif' => 'application/vnd.shana.informed.interchange', 'imp' => 'application/vnd.accpac.simply.imp', 'ims' => 'application/vnd.ms-ims', 'in' => 'text/plain', 'ink' => 'application/inkml+xml', 'inkml' => 'application/inkml+xml', 'install' => 'application/x-install-instructions', 'iota' => 'application/vnd.astraea-software.iota', 'ipfix' => 'application/ipfix', 'ipk' => 'application/vnd.shana.informed.package', 'irm' => 'application/vnd.ibm.rights-management', 'irp' => 'application/vnd.irepository.package+xml', 'iso' => 'application/x-iso9660-image', 'itp' => 'application/vnd.shana.informed.formtemplate', 'ivp' => 'application/vnd.immervision-ivp', 'ivu' => 'application/vnd.immervision-ivu', 'jad' => 'text/vnd.sun.j2me.app-descriptor', 'jam' => 'application/vnd.jam', 'jar' => 'application/java-archive', 'java' => 'text/x-java-source', 'jisp' => 'application/vnd.jisp', 'jlt' => 'application/vnd.hp-jlyt', 'jnlp' => 'application/x-java-jnlp-file', 'joda' => 'application/vnd.joost.joda-archive', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'jpgm' => 'video/jpm', 'jpgv' => 'video/jpeg', 'jpm' => 'video/jpm', 'js' => 'application/javascript', 'json' => 'application/json', 'jsonml' => 'application/jsonml+json', 'kar' => 'audio/midi', 'karbon' => 'application/vnd.kde.karbon', 'kfo' => 'application/vnd.kde.kformula', 'kia' => 'application/vnd.kidspiration', 'kml' => 'application/vnd.google-earth.kml+xml', 'kmz' => 'application/vnd.google-earth.kmz', 'kne' => 'application/vnd.kinar', 'knp' => 'application/vnd.kinar', 'kon' => 'application/vnd.kde.kontour', 'kpr' => 'application/vnd.kde.kpresenter', 'kpt' => 'application/vnd.kde.kpresenter', 'kpxx' => 'application/vnd.ds-keypoint', 'ksp' => 'application/vnd.kde.kspread', 'ktr' => 'application/vnd.kahootz', 'ktx' => 'image/ktx', 'ktz' => 'application/vnd.kahootz', 'kwd' => 'application/vnd.kde.kword', 'kwt' => 'application/vnd.kde.kword', 'lasxml' => 'application/vnd.las.las+xml', 'latex' => 'application/x-latex', 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', 'les' => 'application/vnd.hhe.lesson-player', 'lha' => 'application/x-lzh-compressed', 'link66' => 'application/vnd.route66.link66+xml', 'list' => 'text/plain', 'list3820' => 'application/vnd.ibm.modcap', 'listafp' => 'application/vnd.ibm.modcap', 'lnk' => 'application/x-ms-shortcut', 'log' => 'text/plain', 'lostxml' => 'application/lost+xml', 'lrf' => 'application/octet-stream', 'lrm' => 'application/vnd.ms-lrm', 'ltf' => 'application/vnd.frogans.ltf', 'lvp' => 'audio/vnd.lucent.voice', 'lwp' => 'application/vnd.lotus-wordpro', 'lzh' => 'application/x-lzh-compressed', 'm13' => 'application/x-msmediaview', 'm14' => 'application/x-msmediaview', 'm1v' => 'video/mpeg', 'm21' => 'application/mp21', 'm2a' => 'audio/mpeg', 'm2v' => 'video/mpeg', 'm3a' => 'audio/mpeg', 'm3u' => 'audio/x-mpegurl', 'm3u8' => 'application/vnd.apple.mpegurl', 'm4a' => 'audio/mp4', 'm4u' => 'video/vnd.mpegurl', 'm4v' => 'video/x-m4v', 'ma' => 'application/mathematica', 'mads' => 'application/mads+xml', 'mag' => 'application/vnd.ecowin.chart', 'maker' => 'application/vnd.framemaker', 'man' => 'text/troff', 'mar' => 'application/octet-stream', 'mathml' => 'application/mathml+xml', 'mb' => 'application/mathematica', 'mbk' => 'application/vnd.mobius.mbk', 'mbox' => 'application/mbox', 'mc1' => 'application/vnd.medcalcdata', 'mcd' => 'application/vnd.mcd', 'mcurl' => 'text/vnd.curl.mcurl', 'mdb' => 'application/x-msaccess', 'mdi' => 'image/vnd.ms-modi', 'me' => 'text/troff', 'mesh' => 'model/mesh', 'meta4' => 'application/metalink4+xml', 'metalink' => 'application/metalink+xml', 'mets' => 'application/mets+xml', 'mfm' => 'application/vnd.mfmp', 'mft' => 'application/rpki-manifest', 'mgp' => 'application/vnd.osgeo.mapguide.package', 'mgz' => 'application/vnd.proteus.magazine', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mie' => 'application/x-mie', 'mif' => 'application/vnd.mif', 'mime' => 'message/rfc822', 'mj2' => 'video/mj2', 'mjp2' => 'video/mj2', 'mk3d' => 'video/x-matroska', 'mka' => 'audio/x-matroska', 'mks' => 'video/x-matroska', 'mkv' => 'video/x-matroska', 'mlp' => 'application/vnd.dolby.mlp', 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', 'mmf' => 'application/vnd.smaf', 'mmr' => 'image/vnd.fujixerox.edmics-mmr', 'mng' => 'video/x-mng', 'mny' => 'application/x-msmoney', 'mobi' => 'application/x-mobipocket-ebook', 'mods' => 'application/mods+xml', 'mov' => 'video/quicktime', 'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg', 'mp21' => 'application/mp21', 'mp2a' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', 'mp4a' => 'audio/mp4', 'mp4s' => 'application/mp4', 'mp4v' => 'video/mp4', 'mpc' => 'application/vnd.mophun.certificate', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mpg4' => 'video/mp4', 'mpga' => 'audio/mpeg', 'mpkg' => 'application/vnd.apple.installer+xml', 'mpm' => 'application/vnd.blueice.multipass', 'mpn' => 'application/vnd.mophun.application', 'mpp' => 'application/vnd.ms-project', 'mpt' => 'application/vnd.ms-project', 'mpy' => 'application/vnd.ibm.minipay', 'mqy' => 'application/vnd.mobius.mqy', 'mrc' => 'application/marc', 'mrcx' => 'application/marcxml+xml', 'ms' => 'text/troff', 'mscml' => 'application/mediaservercontrol+xml', 'mseed' => 'application/vnd.fdsn.mseed', 'mseq' => 'application/vnd.mseq', 'msf' => 'application/vnd.epson.msf', 'msh' => 'model/mesh', 'msi' => 'application/x-msdownload', 'msl' => 'application/vnd.mobius.msl', 'msty' => 'application/vnd.muvee.style', 'mts' => 'model/vnd.mts', 'mus' => 'application/vnd.musician', 'musicxml' => 'application/vnd.recordare.musicxml+xml', 'mvb' => 'application/x-msmediaview', 'mwf' => 'application/vnd.mfer', 'mxf' => 'application/mxf', 'mxl' => 'application/vnd.recordare.musicxml', 'mxml' => 'application/xv+xml', 'mxs' => 'application/vnd.triscape.mxs', 'mxu' => 'video/vnd.mpegurl', 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', 'n3' => 'text/n3', 'nb' => 'application/mathematica', 'nbp' => 'application/vnd.wolfram.player', 'nc' => 'application/x-netcdf', 'ncx' => 'application/x-dtbncx+xml', 'nfo' => 'text/x-nfo', 'ngdat' => 'application/vnd.nokia.n-gage.data', 'nitf' => 'application/vnd.nitf', 'nlu' => 'application/vnd.neurolanguage.nlu', 'nml' => 'application/vnd.enliven', 'nnd' => 'application/vnd.noblenet-directory', 'nns' => 'application/vnd.noblenet-sealer', 'nnw' => 'application/vnd.noblenet-web', 'npx' => 'image/vnd.net-fpx', 'nsc' => 'application/x-conference', 'nsf' => 'application/vnd.lotus-notes', 'ntf' => 'application/vnd.nitf', 'nzb' => 'application/x-nzb', 'oa2' => 'application/vnd.fujitsu.oasys2', 'oa3' => 'application/vnd.fujitsu.oasys3', 'oas' => 'application/vnd.fujitsu.oasys', 'obd' => 'application/x-msbinder', 'obj' => 'application/x-tgif', 'oda' => 'application/oda', 'odb' => 'application/vnd.oasis.opendocument.database', 'odc' => 'application/vnd.oasis.opendocument.chart', 'odf' => 'application/vnd.oasis.opendocument.formula', 'odft' => 'application/vnd.oasis.opendocument.formula-template', 'odg' => 'application/vnd.oasis.opendocument.graphics', 'odi' => 'application/vnd.oasis.opendocument.image', 'odm' => 'application/vnd.oasis.opendocument.text-master', 'odp' => 'application/vnd.oasis.opendocument.presentation', 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 'odt' => 'application/vnd.oasis.opendocument.text', 'oga' => 'audio/ogg', 'ogg' => 'audio/ogg', 'ogv' => 'video/ogg', 'ogx' => 'application/ogg', 'omdoc' => 'application/omdoc+xml', 'onepkg' => 'application/onenote', 'onetmp' => 'application/onenote', 'onetoc' => 'application/onenote', 'onetoc2' => 'application/onenote', 'opf' => 'application/oebps-package+xml', 'opml' => 'text/x-opml', 'oprc' => 'application/vnd.palm', 'org' => 'application/vnd.lotus-organizer', 'osf' => 'application/vnd.yamaha.openscoreformat', 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', 'otc' => 'application/vnd.oasis.opendocument.chart-template', 'otf' => 'application/x-font-otf', 'otg' => 'application/vnd.oasis.opendocument.graphics-template', 'oth' => 'application/vnd.oasis.opendocument.text-web', 'oti' => 'application/vnd.oasis.opendocument.image-template', 'otp' => 'application/vnd.oasis.opendocument.presentation-template', 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', 'ott' => 'application/vnd.oasis.opendocument.text-template', 'oxps' => 'application/oxps', 'oxt' => 'application/vnd.openofficeorg.extension', 'p' => 'text/x-pascal', 'p10' => 'application/pkcs10', 'p12' => 'application/x-pkcs12', 'p7b' => 'application/x-pkcs7-certificates', 'p7c' => 'application/pkcs7-mime', 'p7m' => 'application/pkcs7-mime', 'p7r' => 'application/x-pkcs7-certreqresp', 'p7s' => 'application/pkcs7-signature', 'p8' => 'application/pkcs8', 'pas' => 'text/x-pascal', 'paw' => 'application/vnd.pawaafile', 'pbd' => 'application/vnd.powerbuilder6', 'pbm' => 'image/x-portable-bitmap', 'pcap' => 'application/vnd.tcpdump.pcap', 'pcf' => 'application/x-font-pcf', 'pcl' => 'application/vnd.hp-pcl', 'pclxl' => 'application/vnd.hp-pclxl', 'pct' => 'image/x-pict', 'pcurl' => 'application/vnd.curl.pcurl', 'pcx' => 'image/x-pcx', 'pdb' => 'application/vnd.palm', 'pdf' => 'application/pdf', 'pfa' => 'application/x-font-type1', 'pfb' => 'application/x-font-type1', 'pfm' => 'application/x-font-type1', 'pfr' => 'application/font-tdpfr', 'pfx' => 'application/x-pkcs12', 'pgm' => 'image/x-portable-graymap', 'pgn' => 'application/x-chess-pgn', 'pgp' => 'application/pgp-encrypted', 'php' => 'application/x-php', 'php3' => 'application/x-php', 'php4' => 'application/x-php', 'php5' => 'application/x-php', 'pic' => 'image/x-pict', 'pkg' => 'application/octet-stream', 'pki' => 'application/pkixcmp', 'pkipath' => 'application/pkix-pkipath', 'plb' => 'application/vnd.3gpp.pic-bw-large', 'plc' => 'application/vnd.mobius.plc', 'plf' => 'application/vnd.pocketlearn', 'pls' => 'application/pls+xml', 'pml' => 'application/vnd.ctc-posml', 'png' => 'image/png', 'pnm' => 'image/x-portable-anymap', 'portpkg' => 'application/vnd.macports.portpkg', 'pot' => 'application/vnd.ms-powerpoint', 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', 'ppd' => 'application/vnd.cups-ppd', 'ppm' => 'image/x-portable-pixmap', 'pps' => 'application/vnd.ms-powerpoint', 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', 'ppt' => 'application/vnd.ms-powerpoint', 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pqa' => 'application/vnd.palm', 'prc' => 'application/x-mobipocket-ebook', 'pre' => 'application/vnd.lotus-freelance', 'prf' => 'application/pics-rules', 'ps' => 'application/postscript', 'psb' => 'application/vnd.3gpp.pic-bw-small', 'psd' => 'image/vnd.adobe.photoshop', 'psf' => 'application/x-font-linux-psf', 'pskcxml' => 'application/pskc+xml', 'ptid' => 'application/vnd.pvi.ptid1', 'pub' => 'application/x-mspublisher', 'pvb' => 'application/vnd.3gpp.pic-bw-var', 'pwn' => 'application/vnd.3m.post-it-notes', 'pya' => 'audio/vnd.ms-playready.media.pya', 'pyv' => 'video/vnd.ms-playready.media.pyv', 'qam' => 'application/vnd.epson.quickanime', 'qbo' => 'application/vnd.intu.qbo', 'qfx' => 'application/vnd.intu.qfx', 'qps' => 'application/vnd.publishare-delta-tree', 'qt' => 'video/quicktime', 'qwd' => 'application/vnd.quark.quarkxpress', 'qwt' => 'application/vnd.quark.quarkxpress', 'qxb' => 'application/vnd.quark.quarkxpress', 'qxd' => 'application/vnd.quark.quarkxpress', 'qxl' => 'application/vnd.quark.quarkxpress', 'qxt' => 'application/vnd.quark.quarkxpress', 'ra' => 'audio/x-pn-realaudio', 'ram' => 'audio/x-pn-realaudio', 'rar' => 'application/x-rar-compressed', 'ras' => 'image/x-cmu-raster', 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', 'rdf' => 'application/rdf+xml', 'rdz' => 'application/vnd.data-vision.rdz', 'rep' => 'application/vnd.businessobjects', 'res' => 'application/x-dtbresource+xml', 'rgb' => 'image/x-rgb', 'rif' => 'application/reginfo+xml', 'rip' => 'audio/vnd.rip', 'ris' => 'application/x-research-info-systems', 'rl' => 'application/resource-lists+xml', 'rlc' => 'image/vnd.fujixerox.edmics-rlc', 'rld' => 'application/resource-lists-diff+xml', 'rm' => 'application/vnd.rn-realmedia', 'rmi' => 'audio/midi', 'rmp' => 'audio/x-pn-realaudio-plugin', 'rms' => 'application/vnd.jcp.javame.midlet-rms', 'rmvb' => 'application/vnd.rn-realmedia-vbr', 'rnc' => 'application/relax-ng-compact-syntax', 'roa' => 'application/rpki-roa', 'roff' => 'text/troff', 'rp9' => 'application/vnd.cloanto.rp9', 'rpss' => 'application/vnd.nokia.radio-presets', 'rpst' => 'application/vnd.nokia.radio-preset', 'rq' => 'application/sparql-query', 'rs' => 'application/rls-services+xml', 'rsd' => 'application/rsd+xml', 'rss' => 'application/rss+xml', 'rtf' => 'application/rtf', 'rtx' => 'text/richtext', 's' => 'text/x-asm', 's3m' => 'audio/s3m', 'saf' => 'application/vnd.yamaha.smaf-audio', 'sbml' => 'application/sbml+xml', 'sc' => 'application/vnd.ibm.secure-container', 'scd' => 'application/x-msschedule', 'scm' => 'application/vnd.lotus-screencam', 'scq' => 'application/scvp-cv-request', 'scs' => 'application/scvp-cv-response', 'scurl' => 'text/vnd.curl.scurl', 'sda' => 'application/vnd.stardivision.draw', 'sdc' => 'application/vnd.stardivision.calc', 'sdd' => 'application/vnd.stardivision.impress', 'sdkd' => 'application/vnd.solent.sdkm+xml', 'sdkm' => 'application/vnd.solent.sdkm+xml', 'sdp' => 'application/sdp', 'sdw' => 'application/vnd.stardivision.writer', 'see' => 'application/vnd.seemail', 'seed' => 'application/vnd.fdsn.seed', 'sema' => 'application/vnd.sema', 'semd' => 'application/vnd.semd', 'semf' => 'application/vnd.semf', 'ser' => 'application/java-serialized-object', 'setpay' => 'application/set-payment-initiation', 'setreg' => 'application/set-registration-initiation', 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', 'sfs' => 'application/vnd.spotfire.sfs', 'sfv' => 'text/x-sfv', 'sgi' => 'image/sgi', 'sgl' => 'application/vnd.stardivision.writer-global', 'sgm' => 'text/sgml', 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', 'shf' => 'application/shf+xml', 'sid' => 'image/x-mrsid-image', 'sig' => 'application/pgp-signature', 'sil' => 'audio/silk', 'silo' => 'model/mesh', 'sis' => 'application/vnd.symbian.install', 'sisx' => 'application/vnd.symbian.install', 'sit' => 'application/x-stuffit', 'sitx' => 'application/x-stuffitx', 'skd' => 'application/vnd.koan', 'skm' => 'application/vnd.koan', 'skp' => 'application/vnd.koan', 'skt' => 'application/vnd.koan', 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', 'slt' => 'application/vnd.epson.salt', 'sm' => 'application/vnd.stepmania.stepchart', 'smf' => 'application/vnd.stardivision.math', 'smi' => 'application/smil+xml', 'smil' => 'application/smil+xml', 'smv' => 'video/x-smv', 'smzip' => 'application/vnd.stepmania.package', 'snd' => 'audio/basic', 'snf' => 'application/x-font-snf', 'so' => 'application/octet-stream', 'spc' => 'application/x-pkcs7-certificates', 'spf' => 'application/vnd.yamaha.smaf-phrase', 'spl' => 'application/x-futuresplash', 'spot' => 'text/vnd.in3d.spot', 'spp' => 'application/scvp-vp-response', 'spq' => 'application/scvp-vp-request', 'spx' => 'audio/ogg', 'sql' => 'application/x-sql', 'src' => 'application/x-wais-source', 'srt' => 'application/x-subrip', 'sru' => 'application/sru+xml', 'srx' => 'application/sparql-results+xml', 'ssdl' => 'application/ssdl+xml', 'sse' => 'application/vnd.kodak-descriptor', 'ssf' => 'application/vnd.epson.ssf', 'ssml' => 'application/ssml+xml', 'st' => 'application/vnd.sailingtracker.track', 'stc' => 'application/vnd.sun.xml.calc.template', 'std' => 'application/vnd.sun.xml.draw.template', 'stf' => 'application/vnd.wt.stf', 'sti' => 'application/vnd.sun.xml.impress.template', 'stk' => 'application/hyperstudio', 'stl' => 'application/vnd.ms-pki.stl', 'str' => 'application/vnd.pg.format', 'stw' => 'application/vnd.sun.xml.writer.template', 'sub' => 'text/vnd.dvb.subtitle', 'sus' => 'application/vnd.sus-calendar', 'susp' => 'application/vnd.sus-calendar', 'sv4cpio' => 'application/x-sv4cpio', 'sv4crc' => 'application/x-sv4crc', 'svc' => 'application/vnd.dvb.service', 'svd' => 'application/vnd.svd', 'svg' => 'image/svg+xml', 'svgz' => 'image/svg+xml', 'swa' => 'application/x-director', 'swf' => 'application/x-shockwave-flash', 'swi' => 'application/vnd.aristanetworks.swi', 'sxc' => 'application/vnd.sun.xml.calc', 'sxd' => 'application/vnd.sun.xml.draw', 'sxg' => 'application/vnd.sun.xml.writer.global', 'sxi' => 'application/vnd.sun.xml.impress', 'sxm' => 'application/vnd.sun.xml.math', 'sxw' => 'application/vnd.sun.xml.writer', 't' => 'text/troff', 't3' => 'application/x-t3vm-image', 'taglet' => 'application/vnd.mynfc', 'tao' => 'application/vnd.tao.intent-module-archive', 'tar' => 'application/x-tar', 'tcap' => 'application/vnd.3gpp2.tcap', 'tcl' => 'application/x-tcl', 'teacher' => 'application/vnd.smart.teacher', 'tei' => 'application/tei+xml', 'teicorpus' => 'application/tei+xml', 'tex' => 'application/x-tex', 'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', 'text' => 'text/plain', 'tfi' => 'application/thraud+xml', 'tfm' => 'application/x-tex-tfm', 'tga' => 'image/x-tga', 'thmx' => 'application/vnd.ms-officetheme', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'tmo' => 'application/vnd.tmobile-livetv', 'torrent' => 'application/x-bittorrent', 'tpl' => 'application/vnd.groove-tool-template', 'tpt' => 'application/vnd.trid.tpt', 'tr' => 'text/troff', 'tra' => 'application/vnd.trueapp', 'trm' => 'application/x-msterminal', 'tsd' => 'application/timestamped-data', 'tsv' => 'text/tab-separated-values', 'ttc' => 'application/x-font-ttf', 'ttf' => 'application/x-font-ttf', 'ttl' => 'text/turtle', 'twd' => 'application/vnd.simtech-mindmapper', 'twds' => 'application/vnd.simtech-mindmapper', 'txd' => 'application/vnd.genomatix.tuxedo', 'txf' => 'application/vnd.mobius.txf', 'txt' => 'text/plain', 'u32' => 'application/x-authorware-bin', 'udeb' => 'application/x-debian-package', 'ufd' => 'application/vnd.ufdl', 'ufdl' => 'application/vnd.ufdl', 'ulx' => 'application/x-glulx', 'umj' => 'application/vnd.umajin', 'unityweb' => 'application/vnd.unity', 'uoml' => 'application/vnd.uoml+xml', 'uri' => 'text/uri-list', 'uris' => 'text/uri-list', 'urls' => 'text/uri-list', 'ustar' => 'application/x-ustar', 'utz' => 'application/vnd.uiq.theme', 'uu' => 'text/x-uuencode', 'uva' => 'audio/vnd.dece.audio', 'uvd' => 'application/vnd.dece.data', 'uvf' => 'application/vnd.dece.data', 'uvg' => 'image/vnd.dece.graphic', 'uvh' => 'video/vnd.dece.hd', 'uvi' => 'image/vnd.dece.graphic', 'uvm' => 'video/vnd.dece.mobile', 'uvp' => 'video/vnd.dece.pd', 'uvs' => 'video/vnd.dece.sd', 'uvt' => 'application/vnd.dece.ttml+xml', 'uvu' => 'video/vnd.uvvu.mp4', 'uvv' => 'video/vnd.dece.video', 'uvva' => 'audio/vnd.dece.audio', 'uvvd' => 'application/vnd.dece.data', 'uvvf' => 'application/vnd.dece.data', 'uvvg' => 'image/vnd.dece.graphic', 'uvvh' => 'video/vnd.dece.hd', 'uvvi' => 'image/vnd.dece.graphic', 'uvvm' => 'video/vnd.dece.mobile', 'uvvp' => 'video/vnd.dece.pd', 'uvvs' => 'video/vnd.dece.sd', 'uvvt' => 'application/vnd.dece.ttml+xml', 'uvvu' => 'video/vnd.uvvu.mp4', 'uvvv' => 'video/vnd.dece.video', 'uvvx' => 'application/vnd.dece.unspecified', 'uvvz' => 'application/vnd.dece.zip', 'uvx' => 'application/vnd.dece.unspecified', 'uvz' => 'application/vnd.dece.zip', 'vcard' => 'text/vcard', 'vcd' => 'application/x-cdlink', 'vcf' => 'text/x-vcard', 'vcg' => 'application/vnd.groove-vcard', 'vcs' => 'text/x-vcalendar', 'vcx' => 'application/vnd.vcx', 'vis' => 'application/vnd.visionary', 'viv' => 'video/vnd.vivo', 'vob' => 'video/x-ms-vob', 'vor' => 'application/vnd.stardivision.writer', 'vox' => 'application/x-authorware-bin', 'vrml' => 'model/vrml', 'vsd' => 'application/vnd.visio', 'vsf' => 'application/vnd.vsf', 'vss' => 'application/vnd.visio', 'vst' => 'application/vnd.visio', 'vsw' => 'application/vnd.visio', 'vtu' => 'model/vnd.vtu', 'vxml' => 'application/voicexml+xml', 'w3d' => 'application/x-director', 'wad' => 'application/x-doom', 'wav' => 'audio/x-wav', 'wax' => 'audio/x-ms-wax', 'wbmp' => 'image/vnd.wap.wbmp', 'wbs' => 'application/vnd.criticaltools.wbs+xml', 'wbxml' => 'application/vnd.wap.wbxml', 'wcm' => 'application/vnd.ms-works', 'wdb' => 'application/vnd.ms-works', 'wdp' => 'image/vnd.ms-photo', 'weba' => 'audio/webm', 'webm' => 'video/webm', 'webp' => 'image/webp', 'wg' => 'application/vnd.pmi.widget', 'wgt' => 'application/widget', 'wks' => 'application/vnd.ms-works', 'wm' => 'video/x-ms-wm', 'wma' => 'audio/x-ms-wma', 'wmd' => 'application/x-ms-wmd', 'wmf' => 'application/x-msmetafile', 'wml' => 'text/vnd.wap.wml', 'wmlc' => 'application/vnd.wap.wmlc', 'wmls' => 'text/vnd.wap.wmlscript', 'wmlsc' => 'application/vnd.wap.wmlscriptc', 'wmv' => 'video/x-ms-wmv', 'wmx' => 'video/x-ms-wmx', 'wmz' => 'application/x-msmetafile', 'woff' => 'application/font-woff', 'wpd' => 'application/vnd.wordperfect', 'wpl' => 'application/vnd.ms-wpl', 'wps' => 'application/vnd.ms-works', 'wqd' => 'application/vnd.wqd', 'wri' => 'application/x-mswrite', 'wrl' => 'model/vrml', 'wsdl' => 'application/wsdl+xml', 'wspolicy' => 'application/wspolicy+xml', 'wtb' => 'application/vnd.webturbo', 'wvx' => 'video/x-ms-wvx', 'x32' => 'application/x-authorware-bin', 'x3d' => 'model/x3d+xml', 'x3db' => 'model/x3d+binary', 'x3dbz' => 'model/x3d+binary', 'x3dv' => 'model/x3d+vrml', 'x3dvz' => 'model/x3d+vrml', 'x3dz' => 'model/x3d+xml', 'xaml' => 'application/xaml+xml', 'xap' => 'application/x-silverlight-app', 'xar' => 'application/vnd.xara', 'xbap' => 'application/x-ms-xbap', 'xbd' => 'application/vnd.fujixerox.docuworks.binder', 'xbm' => 'image/x-xbitmap', 'xdf' => 'application/xcap-diff+xml', 'xdm' => 'application/vnd.syncml.dm+xml', 'xdp' => 'application/vnd.adobe.xdp+xml', 'xdssc' => 'application/dssc+xml', 'xdw' => 'application/vnd.fujixerox.docuworks', 'xenc' => 'application/xenc+xml', 'xer' => 'application/patch-ops-error+xml', 'xfdf' => 'application/vnd.adobe.xfdf', 'xfdl' => 'application/vnd.xfdl', 'xht' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml', 'xhvml' => 'application/xv+xml', 'xif' => 'image/vnd.xiff', 'xla' => 'application/vnd.ms-excel', 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', 'xlc' => 'application/vnd.ms-excel', 'xlf' => 'application/x-xliff+xml', 'xlm' => 'application/vnd.ms-excel', 'xls' => 'application/vnd.ms-excel', 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlt' => 'application/vnd.ms-excel', 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'xlw' => 'application/vnd.ms-excel', 'xm' => 'audio/xm', 'xml' => 'application/xml', 'xo' => 'application/vnd.olpc-sugar', 'xop' => 'application/xop+xml', 'xpi' => 'application/x-xpinstall', 'xpl' => 'application/xproc+xml', 'xpm' => 'image/x-xpixmap', 'xpr' => 'application/vnd.is-xpr', 'xps' => 'application/vnd.ms-xpsdocument', 'xpw' => 'application/vnd.intercon.formnet', 'xpx' => 'application/vnd.intercon.formnet', 'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml', 'xsm' => 'application/vnd.syncml+xml', 'xspf' => 'application/xspf+xml', 'xul' => 'application/vnd.mozilla.xul+xml', 'xvm' => 'application/xv+xml', 'xvml' => 'application/xv+xml', 'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz', 'xz' => 'application/x-xz', 'yang' => 'application/yang', 'yin' => 'application/yin+xml', 'z1' => 'application/x-zmachine', 'z2' => 'application/x-zmachine', 'z3' => 'application/x-zmachine', 'z4' => 'application/x-zmachine', 'z5' => 'application/x-zmachine', 'z6' => 'application/x-zmachine', 'z7' => 'application/x-zmachine', 'z8' => 'application/x-zmachine', 'zaz' => 'application/vnd.zzazz.deck+xml', 'zip' => 'application/zip', 'zir' => 'application/vnd.zul', 'zirz' => 'application/vnd.zul', 'zmm' => 'application/vnd.handheld-entertainment+xml', '123' => 'application/vnd.lotus-1-2-3', ]; swiftmailer/lib/dependency_maps/transport_deps.php 0000777 00000006601 14710744267 0016604 0 ustar 00 <?php Swift_DependencyContainer::getInstance() ->register('transport.localdomain') // As SERVER_NAME can come from the user in certain configurations, check that // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use // preg_replace() instead of preg_match() to prevent DoS attacks with long host names. ->asValue(!empty($_SERVER['SERVER_NAME']) && '' === preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) ? trim($_SERVER['SERVER_NAME'], '[]') : '127.0.0.1') ->register('transport.smtp') ->asNewInstanceOf('Swift_Transport_EsmtpTransport') ->withDependencies([ 'transport.buffer', 'transport.smtphandlers', 'transport.eventdispatcher', 'transport.localdomain', 'address.idnaddressencoder', ]) ->register('transport.sendmail') ->asNewInstanceOf('Swift_Transport_SendmailTransport') ->withDependencies([ 'transport.buffer', 'transport.eventdispatcher', 'transport.localdomain', ]) ->register('transport.loadbalanced') ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport') ->register('transport.failover') ->asNewInstanceOf('Swift_Transport_FailoverTransport') ->register('transport.spool') ->asNewInstanceOf('Swift_Transport_SpoolTransport') ->withDependencies(['transport.eventdispatcher']) ->register('transport.null') ->asNewInstanceOf('Swift_Transport_NullTransport') ->withDependencies(['transport.eventdispatcher']) ->register('transport.buffer') ->asNewInstanceOf('Swift_Transport_StreamBuffer') ->withDependencies(['transport.replacementfactory']) ->register('transport.smtphandlers') ->asArray() ->withDependencies(['transport.authhandler']) ->register('transport.authhandler') ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler') ->withDependencies(['transport.authhandlers']) ->register('transport.authhandlers') ->asArray() ->withDependencies([ 'transport.crammd5auth', 'transport.loginauth', 'transport.plainauth', 'transport.ntlmauth', 'transport.xoauth2auth', ]) ->register('transport.smtputf8handler') ->asNewInstanceOf('Swift_Transport_Esmtp_SmtpUtf8Handler') ->register('transport.8bitmimehandler') ->asNewInstanceOf('Swift_Transport_Esmtp_EightBitMimeHandler') ->addConstructorValue('8BITMIME') ->register('transport.crammd5auth') ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator') ->register('transport.loginauth') ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator') ->register('transport.plainauth') ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator') ->register('transport.xoauth2auth') ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator') ->register('transport.ntlmauth') ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator') ->register('transport.eventdispatcher') ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher') ->register('transport.replacementfactory') ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory') ->register('address.idnaddressencoder') ->asNewInstanceOf('Swift_AddressEncoder_IdnAddressEncoder') ->register('address.utf8addressencoder') ->asNewInstanceOf('Swift_AddressEncoder_Utf8AddressEncoder') ; swiftmailer/lib/dependency_maps/cache_deps.php 0000777 00000001154 14710744267 0015611 0 ustar 00 <?php Swift_DependencyContainer::getInstance() ->register('cache') ->asAliasOf('cache.array') ->register('tempdir') ->asValue('/tmp') ->register('cache.null') ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache') ->register('cache.array') ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache') ->withDependencies(['cache.inputstream']) ->register('cache.disk') ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache') ->withDependencies(['cache.inputstream', 'tempdir']) ->register('cache.inputstream') ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream') ; swiftmailer/lib/dependency_maps/message_deps.php 0000777 00000000307 14710744267 0016171 0 ustar 00 <?php Swift_DependencyContainer::getInstance() ->register('message.message') ->asNewInstanceOf('Swift_Message') ->register('message.mimepart') ->asNewInstanceOf('Swift_MimePart') ; swiftmailer/lib/dependency_maps/mime_deps.php 0000777 00000011005 14710744267 0015471 0 ustar 00 <?php require __DIR__.'/../mime_types.php'; Swift_DependencyContainer::getInstance() ->register('properties.charset') ->asValue('utf-8') ->register('email.validator') ->asSharedInstanceOf('Egulias\EmailValidator\EmailValidator') ->register('mime.idgenerator.idright') // As SERVER_NAME can come from the user in certain configurations, check that // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use // preg_replace() instead of preg_match() to prevent DoS attacks with long host names. ->asValue(!empty($_SERVER['SERVER_NAME']) && '' === preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated') ->register('mime.idgenerator') ->asSharedInstanceOf('Swift_Mime_IdGenerator') ->withDependencies([ 'mime.idgenerator.idright', ]) ->register('mime.message') ->asNewInstanceOf('Swift_Mime_SimpleMessage') ->withDependencies([ 'mime.headerset', 'mime.textcontentencoder', 'cache', 'mime.idgenerator', 'properties.charset', ]) ->register('mime.part') ->asNewInstanceOf('Swift_Mime_MimePart') ->withDependencies([ 'mime.headerset', 'mime.textcontentencoder', 'cache', 'mime.idgenerator', 'properties.charset', ]) ->register('mime.attachment') ->asNewInstanceOf('Swift_Mime_Attachment') ->withDependencies([ 'mime.headerset', 'mime.base64contentencoder', 'cache', 'mime.idgenerator', ]) ->addConstructorValue($swift_mime_types) ->register('mime.embeddedfile') ->asNewInstanceOf('Swift_Mime_EmbeddedFile') ->withDependencies([ 'mime.headerset', 'mime.base64contentencoder', 'cache', 'mime.idgenerator', ]) ->addConstructorValue($swift_mime_types) ->register('mime.headerfactory') ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') ->withDependencies([ 'mime.qpheaderencoder', 'mime.rfc2231encoder', 'email.validator', 'properties.charset', 'address.idnaddressencoder', ]) ->register('mime.headerset') ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet') ->withDependencies(['mime.headerfactory', 'properties.charset']) ->register('mime.qpheaderencoder') ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder') ->withDependencies(['mime.charstream']) ->register('mime.base64headerencoder') ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder') ->withDependencies(['mime.charstream']) ->register('mime.charstream') ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream') ->withDependencies(['mime.characterreaderfactory', 'properties.charset']) ->register('mime.bytecanonicalizer') ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter') ->addConstructorValue([[0x0D, 0x0A], [0x0D], [0x0A]]) ->addConstructorValue([[0x0A], [0x0A], [0x0D, 0x0A]]) ->register('mime.characterreaderfactory') ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory') ->register('mime.textcontentencoder') ->asAliasOf('mime.qpcontentencoder') ->register('mime.safeqpcontentencoder') ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') ->withDependencies(['mime.charstream', 'mime.bytecanonicalizer']) ->register('mime.rawcontentencoder') ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder') ->register('mime.nativeqpcontentencoder') ->withDependencies(['properties.charset']) ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder') ->register('mime.qpcontentencoder') ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy') ->withDependencies(['mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset']) ->register('mime.7bitcontentencoder') ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') ->addConstructorValue('7bit') ->addConstructorValue(true) ->register('mime.8bitcontentencoder') ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') ->addConstructorValue('8bit') ->addConstructorValue(true) ->register('mime.base64contentencoder') ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder') ->register('mime.rfc2231encoder') ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder') ->withDependencies(['mime.charstream']) ; unset($swift_mime_types); swiftmailer/lib/swiftmailer_generate_mimes_config.php 0000777 00000016462 14710744267 0017324 0 ustar 00 #!/usr/bin/php <?php \define('APACHE_MIME_TYPES_URL', 'https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types'); \define('FREEDESKTOP_XML_URL', 'https://raw.github.com/minad/mimemagic/master/script/freedesktop.org.xml'); function generateUpToDateMimeArray() { $preamble = "<?php\n\n"; $preamble .= "/*\n"; $preamble .= " * This file is part of SwiftMailer.\n"; $preamble .= " * (c) 2004-2009 Chris Corbyn\n *\n"; $preamble .= " * For the full copyright and license information, please view the LICENSE\n"; $preamble .= " * file that was distributed with this source code.\n *\n"; $preamble .= " * autogenerated using https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types\n"; $preamble .= " * and https://raw.github.com/minad/mimemagic/master/script/freedesktop.org.xml\n"; $preamble .= " */\n\n"; $preamble .= "/*\n"; $preamble .= " * List of MIME type automatically detected in Swift Mailer.\n"; $preamble .= " */\n\n"; $preamble .= "// You may add or take away what you like (lowercase required)\n\n"; // get current mime types files $mime_types = @file_get_contents(APACHE_MIME_TYPES_URL); $mime_xml = @file_get_contents(FREEDESKTOP_XML_URL); // prepare valid mime types $valid_mime_types = []; // split mime type and extensions eg. "video/x-matroska mkv mk3d mks" if (false !== preg_match_all('/^#?([a-z0-9\-\+\/\.]+)[\t]+(.*)$/miu', $mime_types, $matches)) { // collection of predefined mimetypes (bugfix for wrong resolved or missing mime types) $valid_mime_types_preset = [ 'php' => 'application/x-php', 'php3' => 'application/x-php', 'php4' => 'application/x-php', 'php5' => 'application/x-php', 'zip' => 'application/zip', 'gif' => 'image/gif', 'png' => 'image/png', 'css' => 'text/css', 'js' => 'text/javascript', 'txt' => 'text/plain', 'aif' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'avi' => 'video/avi', 'bmp' => 'image/bmp', 'bz2' => 'application/x-bz2', 'csv' => 'text/csv', 'dmg' => 'application/x-apple-diskimage', 'doc' => 'application/msword', 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'eml' => 'message/rfc822', 'aps' => 'application/postscript', 'exe' => 'application/x-ms-dos-executable', 'flv' => 'video/x-flv', 'gz' => 'application/x-gzip', 'hqx' => 'application/stuffit', 'htm' => 'text/html', 'html' => 'text/html', 'jar' => 'application/x-java-archive', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'm3u' => 'audio/x-mpegurl', 'm4a' => 'audio/mp4', 'mdb' => 'application/x-msaccess', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mov' => 'video/quicktime', 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'odg' => 'vnd.oasis.opendocument.graphics', 'odp' => 'vnd.oasis.opendocument.presentation', 'odt' => 'vnd.oasis.opendocument.text', 'ods' => 'vnd.oasis.opendocument.spreadsheet', 'ogg' => 'audio/ogg', 'pdf' => 'application/pdf', 'ppt' => 'application/vnd.ms-powerpoint', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'ps' => 'application/postscript', 'rar' => 'application/x-rar-compressed', 'rtf' => 'application/rtf', 'tar' => 'application/x-tar', 'sit' => 'application/x-stuffit', 'svg' => 'image/svg+xml', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ttf' => 'application/x-font-truetype', 'vcf' => 'text/x-vcard', 'wav' => 'audio/wav', 'wma' => 'audio/x-ms-wma', 'wmv' => 'audio/x-ms-wmv', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xml' => 'application/xml', ]; // wrap array for generating file foreach ($valid_mime_types_preset as $extension => $mime_type) { // generate array for mimetype to extension resolver (only first match) $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; } // all extensions from second match foreach ($matches[2] as $i => $extensions) { // explode multiple extensions from string $extensions = explode(' ', strtolower($extensions ?? '')); // force array for foreach if (!\is_array($extensions)) { $extensions = [$extensions]; } foreach ($extensions as $extension) { // get mime type $mime_type = $matches[1][$i]; // check if string length lower than 10 if (\strlen($extension) < 10) { if (!isset($valid_mime_types[$mime_type])) { // generate array for mimetype to extension resolver (only first match) $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; } } } } } $xml = simplexml_load_string($mime_xml); foreach ($xml as $node) { // check if there is no pattern if (!isset($node->glob['pattern'])) { continue; } // get all matching extensions from match foreach ((array) $node->glob['pattern'] as $extension) { // skip none glob extensions if (false === strpos($extension ?? '', '.')) { continue; } // remove get only last part $extension = explode('.', strtolower($extension ?? '')); $extension = end($extension); } if (isset($node->glob['pattern'][0])) { // mime type $mime_type = strtolower((string) $node['type'] ?? ''); // get first extension $extension = strtolower(trim($node->glob['ddpattern'][0] ?? '', '*.')); // skip none glob extensions and check if string length between 1 and 10 if (false !== strpos($extension, '.') || \strlen($extension) < 1 || \strlen($extension) > 9) { continue; } // check if string length lower than 10 if (!isset($valid_mime_types[$mime_type])) { // generate array for mimetype to extension resolver (only first match) $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; } } } // full list of valid extensions only $valid_mime_types = array_unique($valid_mime_types); ksort($valid_mime_types); // combine mime types and extensions array $output = "$preamble\$swift_mime_types = array(\n ".implode(",\n ", $valid_mime_types)."\n);"; // write mime_types.php config file @file_put_contents('./mime_types.php', $output); } generateUpToDateMimeArray(); swiftmailer/lib/swift_required.php 0000777 00000001170 14710744267 0013427 0 ustar 00 <?php /* * This file is part of SwiftMailer. * (c) 2004-2009 Chris Corbyn * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ require __DIR__.'/classes/Swift.php'; Swift::registerAutoload(function () { // Load in dependency maps require __DIR__.'/dependency_maps/cache_deps.php'; require __DIR__.'/dependency_maps/mime_deps.php'; require __DIR__.'/dependency_maps/message_deps.php'; require __DIR__.'/dependency_maps/transport_deps.php'; // Load in global library preferences require __DIR__.'/preferences.php'; }); swiftmailer/lib/preferences.php 0000777 00000001656 14710744267 0012705 0 ustar 00 <?php /****************************************************************************/ /* */ /* YOU MAY WISH TO MODIFY OR REMOVE THE FOLLOWING LINES WHICH SET DEFAULTS */ /* */ /****************************************************************************/ $preferences = Swift_Preferences::getInstance(); // Sets the default charset so that setCharset() is not needed elsewhere $preferences->setCharset('utf-8'); // Without these lines the default caching mechanism is "array" but this uses a lot of memory. // If possible, use a disk cache to enable attaching large attachments etc. // You can override the default temporary directory by setting the TMPDIR environment variable. if (@is_writable($tmpDir = sys_get_temp_dir())) { $preferences->setTempDir($tmpDir)->setCacheType('disk'); } swiftmailer/composer.json 0000777 00000002207 14710744267 0011640 0 ustar 00 { "name": "swiftmailer/swiftmailer", "type": "library", "description": "Swiftmailer, free feature-rich PHP mailer", "keywords": ["mail","mailer","email"], "homepage": "https://swiftmailer.symfony.com", "license": "MIT", "authors": [ { "name": "Chris Corbyn" }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" } ], "require": { "php": ">=7.0.0", "egulias/email-validator": "^2.0|^3.1", "symfony/polyfill-iconv": "^1.0", "symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-intl-idn": "^1.10" }, "require-dev": { "mockery/mockery": "^1.0", "symfony/phpunit-bridge": "^4.4|^5.4" }, "suggest": { "ext-intl": "Needed to support internationalized email addresses" }, "autoload": { "files": ["lib/swift_required.php"] }, "autoload-dev": { "psr-0": { "Swift_": "tests/unit" } }, "extra": { "branch-alias": { "dev-master": "6.2-dev" } }, "minimum-stability": "dev", "prefer-stable": true } swiftmailer/doc/introduction.rst 0000777 00000004030 14710744267 0013132 0 ustar 00 Swiftmailer: A feature-rich PHP Mailer ====================================== Swift Mailer is a component based library for sending e-mails from PHP applications. **Swiftmailer will stop being maintained at the end of November 2021.** Please, move to `Symfony Mailer <https://symfony.com/doc/current/mailer.html>`_ at your earliest convenience. `Symfony Mailer <https://symfony.com/doc/current/mailer.html>`_ is the next evolution of Swiftmailer. It provides the same features with support for modern PHP code and support for third-party providers. System Requirements ------------------- Swift Mailer requires PHP 7.0 or higher (``proc_*`` functions must be available). Swift Mailer does not work when used with function overloading as implemented by ``mbstring`` when ``mbstring.func_overload`` is set to ``2``. Installation ------------ The recommended way to install Swiftmailer is via Composer: .. code-block:: bash $ composer require "swiftmailer/swiftmailer:^6.0" Basic Usage ----------- Here is the simplest way to send emails with Swift Mailer:: require_once '/path/to/vendor/autoload.php'; // Create the Transport $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) ->setUsername('your username') ->setPassword('your password') ; // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); // Create a message $message = (new Swift_Message('Wonderful Subject')) ->setFrom(['john@doe.com' => 'John Doe']) ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) ->setBody('Here is the message itself') ; // Send the message $result = $mailer->send($message); You can also use Sendmail as a transport:: // Sendmail $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs'); Getting Help ------------ For general support, use `Stack Overflow <https://stackoverflow.com>`_. For bug reports and feature requests, create a new ticket in `GitHub <https://github.com/swiftmailer/swiftmailer/issues>`_. swiftmailer/doc/messages.rst 0000777 00000116670 14710744267 0012236 0 ustar 00 Creating Messages ================= Creating messages in Swift Mailer is done by making use of the various MIME entities provided with the library. Complex messages can be quickly created with very little effort. Quick Reference --------------- You can think of creating a Message as being similar to the steps you perform when you click the Compose button in your mail client. You give it a subject, specify some recipients, add any attachments and write your message:: // Create the message $message = (new Swift_Message()) // Give the message a subject ->setSubject('Your subject') // Set the From address with an associative array ->setFrom(['john@doe.com' => 'John Doe']) // Set the To addresses with an associative array (setTo/setCc/setBcc) ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) // Give it a body ->setBody('Here is the message itself') // And optionally an alternative body ->addPart('<q>Here is the message itself</q>', 'text/html') // Optionally add any attachments ->attach(Swift_Attachment::fromPath('my-document.pdf')) ; Message Basics -------------- A message is a container for anything you want to send to somebody else. There are several basic aspects of a message that you should know. An e-mail message is made up of several relatively simple entities that are combined in different ways to achieve different results. All of these entities have the same fundamental outline but serve a different purpose. The Message itself can be defined as a MIME entity, an Attachment is a MIME entity, all MIME parts are MIME entities -- and so on! The basic units of each MIME entity -- be it the Message itself, or an Attachment -- are its Headers and its body: .. code-block:: text Header-Name: A header value Other-Header: Another value The body content itself The Headers of a MIME entity, and its body must conform to some strict standards defined by various RFC documents. Swift Mailer ensures that these specifications are followed by using various types of object, including Encoders and different Header types to generate the entity. The Structure of a Message ~~~~~~~~~~~~~~~~~~~~~~~~~~ Of all of the MIME entities, a message -- ``Swift_Message`` is the largest and most complex. It has many properties that can be updated and it can contain other MIME entities -- attachments for example -- nested inside it. A Message has a lot of different Headers which are there to present information about the message to the recipients' mail client. Most of these headers will be familiar to the majority of users, but we'll list the basic ones. Although it's possible to work directly with the Headers of a Message (or other MIME entity), the standard Headers have accessor methods provided to abstract away the complex details for you. For example, although the Date on a message is written with a strict format, you only need to pass a DateTimeInterface instance to ``setDate()``. +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | Header | Description | Accessors | +===============================+====================================================================================================================================+=============================================+ | ``Message-ID`` | Identifies this message with a unique ID, usually containing the domain name and time generated | ``getId()`` / ``setId()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Return-Path`` | Specifies where bounces should go (Swift Mailer reads this for other uses) | ``getReturnPath()`` / ``setReturnPath()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``From`` | Specifies the address of the person who the message is from. This can be multiple addresses if multiple people wrote the message. | ``getFrom()`` / ``setFrom()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Sender`` | Specifies the address of the person who physically sent the message (higher precedence than ``From:``) | ``getSender()`` / ``setSender()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``To`` | Specifies the addresses of the intended recipients | ``getTo()`` / ``setTo()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Cc`` | Specifies the addresses of recipients who will be copied in on the message | ``getCc()`` / ``setCc()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Bcc`` | Specifies the addresses of recipients who the message will be blind-copied to. Other recipients will not be aware of these copies. | ``getBcc()`` / ``setBcc()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Reply-To`` | Specifies the address where replies are sent to | ``getReplyTo()`` / ``setReplyTo()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Subject`` | Specifies the subject line that is displayed in the recipients' mail client | ``getSubject()`` / ``setSubject()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Date`` | Specifies the date at which the message was sent | ``getDate()`` / ``setDate()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Content-Type`` | Specifies the format of the message (usually ``text/plain`` or ``text/html``) | ``getContentType()`` / ``setContentType()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ | ``Content-Transfer-Encoding`` | Specifies the encoding scheme in the message | ``getEncoder()`` / ``setEncoder()`` | +-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+ Working with a Message Object ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Although there are a lot of available methods on a message object, you only need to make use of a small subset of them. Usually you'll use ``setSubject()``, ``setTo()`` and ``setFrom()`` before setting the body of your message with ``setBody()``:: $message = new Swift_Message(); $message->setSubject('My subject'); All MIME entities (including a message) have a ``toString()`` method that you can call if you want to take a look at what is going to be sent. For example, if you ``echo $message->toString();`` you would see something like this: .. code-block:: text Message-ID: <1230173678.4952f5eeb1432@swift.generated> Date: Thu, 25 Dec 2008 13:54:38 +1100 Subject: Example subject From: Chris Corbyn <chris@w3style.co.uk> To: Receiver Name <recipient@example.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Here is the message We'll take a closer look at the methods you use to create your message in the following sections. Adding Content to Your Message ------------------------------ Rich content can be added to messages in Swift Mailer with relative ease by calling methods such as ``setSubject()``, ``setBody()``, ``addPart()`` and ``attach()``. Setting the Subject Line ~~~~~~~~~~~~~~~~~~~~~~~~ The subject line, displayed in the recipients' mail client can be set with the ``setSubject()`` method, or as a parameter to ``new Swift_Message()``:: // Pass it as a parameter when you create the message $message = new Swift_Message('My amazing subject'); // Or set it after like this $message->setSubject('My amazing subject'); Setting the Body Content ~~~~~~~~~~~~~~~~~~~~~~~~ The body of the message -- seen when the user opens the message -- is specified by calling the ``setBody()`` method. If an alternative body is to be included, ``addPart()`` can be used. The body of a message is the main part that is read by the user. Often people want to send a message in HTML format (``text/html``), other times people want to send in plain text (``text/plain``), or sometimes people want to send both versions and allow the recipient to choose how they view the message. As a rule of thumb, if you're going to send a HTML email, always include a plain-text equivalent of the same content so that users who prefer to read plain text can do so. If the recipient's mail client offers preferences for displaying text vs. HTML then the mail client will present that part to the user where available. In other cases the mail client will display the "best" part it can - usually HTML if you've included HTML:: // Pass it as a parameter when you create the message $message = new Swift_Message('Subject here', 'My amazing body'); // Or set it after like this $message->setBody('My <em>amazing</em> body', 'text/html'); // Add alternative parts with addPart() $message->addPart('My amazing body in plain text', 'text/plain'); Attaching Files --------------- Attachments are downloadable parts of a message and can be added by calling the ``attach()`` method on the message. You can add attachments that exist on disk, or you can create attachments on-the-fly. Although we refer to files sent over e-mails as "attachments" -- because they're attached to the message -- lots of other parts of the message are actually "attached" even if we don't refer to these parts as attachments. File attachments are created by the ``Swift_Attachment`` class and then attached to the message via the ``attach()`` method on it. For all of the "every day" MIME types such as all image formats, word documents, PDFs and spreadsheets you don't need to explicitly set the content-type of the attachment, though it would do no harm to do so. For less common formats you should set the content-type -- which we'll cover in a moment. Attaching Existing Files ~~~~~~~~~~~~~~~~~~~~~~~~ Files that already exist, either on disk or at a URL can be attached to a message with just one line of code, using ``Swift_Attachment::fromPath()``. You can attach files that exist locally, or if your PHP installation has ``allow_url_fopen`` turned on you can attach files from other websites. The attachment will be presented to the recipient as a downloadable file with the same filename as the one you attached:: // Create the attachment // * Note that you can technically leave the content-type parameter out $attachment = Swift_Attachment::fromPath('/path/to/image.jpg', 'image/jpeg'); // Attach it to the message $message->attach($attachment); // The two statements above could be written in one line instead $message->attach(Swift_Attachment::fromPath('/path/to/image.jpg')); // You can attach files from a URL if allow_url_fopen is on in php.ini $message->attach(Swift_Attachment::fromPath('http://site.tld/logo.png')); Setting the Filename ~~~~~~~~~~~~~~~~~~~~ Usually you don't need to explicitly set the filename of an attachment because the name of the attached file will be used by default, but if you want to set the filename you use the ``setFilename()`` method of the Attachment. The attachment will be attached in the normal way, but meta-data sent inside the email will rename the file to something else:: // Create the attachment and call its setFilename() method $attachment = Swift_Attachment::fromPath('/path/to/image.jpg') ->setFilename('cool.jpg'); // Because there's a fluid interface, you can do this in one statement $message->attach( Swift_Attachment::fromPath('/path/to/image.jpg')->setFilename('cool.jpg') ); Attaching Dynamic Content ~~~~~~~~~~~~~~~~~~~~~~~~~ Files that are generated at runtime, such as PDF documents or images created via GD can be attached directly to a message without writing them out to disk. Use ``Swift_Attachment`` directly. The attachment will be presented to the recipient as a downloadable file with the filename and content-type you specify:: // Create your file contents in the normal way, but don't write them to disk $data = create_my_pdf_data(); // Create the attachment with your data $attachment = new Swift_Attachment($data, 'my-file.pdf', 'application/pdf'); // Attach it to the message $message->attach($attachment); // You can alternatively use method chaining to build the attachment $attachment = (new Swift_Attachment()) ->setFilename('my-file.pdf') ->setContentType('application/pdf') ->setBody($data) ; .. note:: If you would usually write the file to disk anyway you should just attach it with ``Swift_Attachment::fromPath()`` since this will use less memory. Changing the Disposition ~~~~~~~~~~~~~~~~~~~~~~~~ Attachments just appear as files that can be saved to the Desktop if desired. You can make attachment appear inline where possible by using the ``setDisposition()`` method of an attachment. The attachment will be displayed within the email viewing window if the mail client knows how to display it:: // Create the attachment and call its setDisposition() method $attachment = Swift_Attachment::fromPath('/path/to/image.jpg') ->setDisposition('inline'); // Because there's a fluid interface, you can do this in one statement $message->attach( Swift_Attachment::fromPath('/path/to/image.jpg')->setDisposition('inline') ); .. note:: If you try to create an inline attachment for a non-displayable file type such as a ZIP file, the mail client should just present the attachment as normal. Embedding Inline Media Files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Often, people want to include an image or other content inline with a HTML message. It's easy to do this with HTML linking to remote resources, but this approach is usually blocked by mail clients. Swift Mailer allows you to embed your media directly into the message. Mail clients usually block downloads from remote resources because this technique was often abused as a mean of tracking who opened an email. If you're sending a HTML email and you want to include an image in the message another approach you can take is to embed the image directly. Swift Mailer makes embedding files into messages extremely streamlined. You embed a file by calling the ``embed()`` method of the message, which returns a value you can use in a ``src`` or ``href`` attribute in your HTML. Just like with attachments, it's possible to embed dynamically generated content without having an existing file available. The embedded files are sent in the email as a special type of attachment that has a unique ID used to reference them within your HTML attributes. On mail clients that do not support embedded files they may appear as attachments. Although this is commonly done for images, in theory it will work for any displayable (or playable) media type. Support for other media types (such as video) is dependent on the mail client however. Embedding Existing Files ........................ Files that already exist, either on disk or at a URL can be embedded in a message with just one line of code, using ``Swift_EmbeddedFile::fromPath()``. You can embed files that exist locally, or if your PHP installation has ``allow_url_fopen`` turned on you can embed files from other websites. The file will be displayed with the message inline with the HTML wherever its ID is used as a ``src`` attribute:: // Create the message $message = new Swift_Message('My subject'); // Set the body $message->setBody( '<html>' . ' <body>' . ' Here is an image <img src="' . // Embed the file $message->embed(Swift_Image::fromPath('image.png')) . '" alt="Image" />' . ' Rest of message' . ' </body>' . '</html>', 'text/html' // Mark the content-type as HTML ); // You can embed files from a URL if allow_url_fopen is on in php.ini $message->setBody( '<html>' . ' <body>' . ' Here is an image <img src="' . $message->embed(Swift_Image::fromPath('http://site.tld/logo.png')) . '" alt="Image" />' . ' Rest of message' . ' </body>' . '</html>', 'text/html' ); .. note:: ``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one another. ``Swift_Image`` exists for semantic purposes. .. note:: You can embed files in two stages if you prefer. Just capture the return value of ``embed()`` in a variable and use that as the ``src`` attribute:: // If placing the embed() code inline becomes cumbersome // it's easy to do this in two steps $cid = $message->embed(Swift_Image::fromPath('image.png')); $message->setBody( '<html>' . ' <body>' . ' Here is an image <img src="' . $cid . '" alt="Image" />' . ' Rest of message' . ' </body>' . '</html>', 'text/html' // Mark the content-type as HTML ); Embedding Dynamic Content ......................... Images that are generated at runtime, such as images created via GD can be embedded directly to a message without writing them out to disk. Use the standard ``new Swift_Image()`` method. The file will be displayed with the message inline with the HTML wherever its ID is used as a ``src`` attribute:: // Create your file contents in the normal way, but don't write them to disk $img_data = create_my_image_data(); // Create the message $message = new Swift_Message('My subject'); // Set the body $message->setBody( '<html>' . ' <body>' . ' Here is an image <img src="' . // Embed the file $message->embed(new Swift_Image($img_data, 'image.jpg', 'image/jpeg')) . '" alt="Image" />' . ' Rest of message' . ' </body>' . '</html>', 'text/html' // Mark the content-type as HTML ); .. note:: ``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one another. ``Swift_Image`` exists for semantic purposes. .. note:: You can embed files in two stages if you prefer. Just capture the return value of ``embed()`` in a variable and use that as the ``src`` attribute:: // If placing the embed() code inline becomes cumbersome // it's easy to do this in two steps $cid = $message->embed(new Swift_Image($img_data, 'image.jpg', 'image/jpeg')); $message->setBody( '<html>' . ' <body>' . ' Here is an image <img src="' . $cid . '" alt="Image" />' . ' Rest of message' . ' </body>' . '</html>', 'text/html' // Mark the content-type as HTML ); Adding Recipients to Your Message --------------------------------- Recipients are specified within the message itself via ``setTo()``, ``setCc()`` and ``setBcc()``. Swift Mailer reads these recipients from the message when it gets sent so that it knows where to send the message to. Message recipients are one of three types: * ``To:`` recipients -- the primary recipients (required) * ``Cc:`` recipients -- receive a copy of the message (optional) * ``Bcc:`` recipients -- hidden from other recipients (optional) Each type can contain one, or several addresses. It's possible to list only the addresses of the recipients, or you can personalize the address by providing the real name of the recipient. Make sure to add only valid email addresses as recipients. If you try to add an invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift Mailer will throw a ``Swift_RfcComplianceException``. If you add recipients automatically based on a data source that may contain invalid email addresses, you can prevent possible exceptions by validating the addresses using:: use Egulias\EmailValidator\EmailValidator; use Egulias\EmailValidator\Validation\RFCValidation; $validator = new EmailValidator(); $validator->isValid("example@example.com", new RFCValidation()); //true and only adding addresses that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and ``setBcc()`` calls in a try-catch block and handle the ``Swift_RfcComplianceException`` in the catch block. .. sidebar:: Syntax for Addresses If you only wish to refer to a single email address (for example your ``From:`` address) then you can just use a string:: $message->setFrom('some@address.tld'); If you want to include a name then you must use an associative array:: $message->setFrom(['some@address.tld' => 'The Name']); If you want to include multiple addresses then you must use an array:: $message->setTo(['some@address.tld', 'other@address.tld']); You can mix personalized (addresses with a name) and non-personalized addresses in the same list by mixing the use of associative and non-associative array syntax:: $message->setTo([ 'recipient-with-name@example.org' => 'Recipient Name One', 'no-name@example.org', // Note that this is not a key-value pair 'named-recipient@example.org' => 'Recipient Name Two' ]); Setting ``To:`` Recipients ~~~~~~~~~~~~~~~~~~~~~~~~~~ ``To:`` recipients are required in a message and are set with the ``setTo()`` or ``addTo()`` methods of the message. To set ``To:`` recipients, create the message object using either ``new Swift_Message( ... )``, then call the ``setTo()`` method with a complete array of addresses, or use the ``addTo()`` method to iteratively add recipients. The ``setTo()`` method accepts input in various formats as described earlier in this chapter. The ``addTo()`` method takes either one or two parameters. The first being the email address and the second optional parameter being the name of the recipient. ``To:`` recipients are visible in the message headers and will be seen by the other recipients:: // Using setTo() to set all recipients in one go $message->setTo([ 'person1@example.org', 'person2@otherdomain.org' => 'Person 2 Name', 'person3@example.org', 'person4@example.org', 'person5@example.org' => 'Person 5 Name' ]); .. note:: Multiple calls to ``setTo()`` will not add new recipients -- each call overrides the previous calls. If you want to iteratively add recipients, use the ``addTo()`` method:: // Using addTo() to add recipients iteratively $message->addTo('person1@example.org'); $message->addTo('person2@example.org', 'Person 2 Name'); Setting ``Cc:`` Recipients ~~~~~~~~~~~~~~~~~~~~~~~~~~ ``Cc:`` recipients are set with the ``setCc()`` or ``addCc()`` methods of the message. To set ``Cc:`` recipients, create the message object using either ``new Swift_Message( ... )``, then call the ``setCc()`` method with a complete array of addresses, or use the ``addCc()`` method to iteratively add recipients. The ``setCc()`` method accepts input in various formats as described earlier in this chapter. The ``addCc()`` method takes either one or two parameters. The first being the email address and the second optional parameter being the name of the recipient. ``Cc:`` recipients are visible in the message headers and will be seen by the other recipients:: // Using setTo() to set all recipients in one go $message->setTo([ 'person1@example.org', 'person2@otherdomain.org' => 'Person 2 Name', 'person3@example.org', 'person4@example.org', 'person5@example.org' => 'Person 5 Name' ]); .. note:: Multiple calls to ``setCc()`` will not add new recipients -- each call overrides the previous calls. If you want to iteratively add Cc: recipients, use the ``addCc()`` method:: // Using addCc() to add recipients iteratively $message->addCc('person1@example.org'); $message->addCc('person2@example.org', 'Person 2 Name'); Setting ``Bcc:`` Recipients ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``Bcc:`` recipients receive a copy of the message without anybody else knowing it, and are set with the ``setBcc()`` or ``addBcc()`` methods of the message. To set ``Bcc:`` recipients, create the message object using either ``new Swift_Message( ... )``, then call the ``setBcc()`` method with a complete array of addresses, or use the ``addBcc()`` method to iteratively add recipients. The ``setBcc()`` method accepts input in various formats as described earlier in this chapter. The ``addBcc()`` method takes either one or two parameters. The first being the email address and the second optional parameter being the name of the recipient. Only the individual ``Bcc:`` recipient will see their address in the message headers. Other recipients (including other ``Bcc:`` recipients) will not see the address:: // Using setBcc() to set all recipients in one go $message->setBcc([ 'person1@example.org', 'person2@otherdomain.org' => 'Person 2 Name', 'person3@example.org', 'person4@example.org', 'person5@example.org' => 'Person 5 Name' ]); .. note:: Multiple calls to ``setBcc()`` will not add new recipients -- each call overrides the previous calls. If you want to iteratively add Bcc: recipients, use the ``addBcc()`` method:: // Using addBcc() to add recipients iteratively $message->addBcc('person1@example.org'); $message->addBcc('person2@example.org', 'Person 2 Name'); .. sidebar:: Internationalized Email Addresses Traditionally only ASCII characters have been allowed in email addresses. With the introduction of internationalized domain names (IDNs), non-ASCII characters may appear in the domain name. By default, Swiftmailer encodes such domain names in Punycode (e.g. xn--xample-ova.invalid). This is compatible with all mail servers. RFC 6531 introduced an SMTP extension, SMTPUTF8, that allows non-ASCII characters in email addresses on both sides of the @ sign. To send to such addresses, your outbound SMTP server must support the SMTPUTF8 extension. You should use the ``Swift_AddressEncoder_Utf8AddressEncoder`` address encoder and enable the ``Swift_Transport_Esmtp_SmtpUtf8Handler`` SMTP extension handler:: $smtpUtf8 = new Swift_Transport_Esmtp_SmtpUtf8Handler(); $transport->setExtensionHandlers([$smtpUtf8]); $utf8Encoder = new Swift_AddressEncoder_Utf8AddressEncoder(); $transport->setAddressEncoder($utf8Encoder); Specifying Sender Details ------------------------- An email must include information about who sent it. Usually this is managed by the ``From:`` address, however there are other options. The sender information is contained in three possible places: * ``From:`` -- the address(es) of who wrote the message (required) * ``Sender:`` -- the address of the single person who sent the message (optional) * ``Return-Path:`` -- the address where bounces should go to (optional) You must always include a ``From:`` address by using ``setFrom()`` on the message. Swift Mailer will use this as the default ``Return-Path:`` unless otherwise specified. The ``Sender:`` address exists because the person who actually sent the email may not be the person who wrote the email. It has a higher precedence than the ``From:`` address and will be used as the ``Return-Path:`` unless otherwise specified. Setting the ``From:`` Address ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``From:`` address is required and is set with the ``setFrom()`` method of the message. ``From:`` addresses specify who actually wrote the email, and usually who sent it. What most people probably don't realize is that you can have more than one ``From:`` address if more than one person wrote the email -- for example if an email was put together by a committee. The ``From:`` address(es) are visible in the message headers and will be seen by the recipients. .. note:: If you set multiple ``From:`` addresses then you absolutely must set a ``Sender:`` address to indicate who physically sent the message. :: // Set a single From: address $message->setFrom('your@address.tld'); // Set a From: address including a name $message->setFrom(['your@address.tld' => 'Your Name']); // Set multiple From: addresses if multiple people wrote the email $message->setFrom([ 'person1@example.org' => 'Sender One', 'person2@example.org' => 'Sender Two' ]); Setting the ``Sender:`` Address ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``Sender:`` address specifies who sent the message and is set with the ``setSender()`` method of the message. The ``Sender:`` address is visible in the message headers and will be seen by the recipients. This address will be used as the ``Return-Path:`` unless otherwise specified. .. note:: If you set multiple ``From:`` addresses then you absolutely must set a ``Sender:`` address to indicate who physically sent the message. You must not set more than one sender address on a message because it's not possible for more than one person to send a single message:: $message->setSender('your@address.tld'); Setting the ``Return-Path:`` (Bounce) Address ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``Return-Path:`` address specifies where bounce notifications should be sent and is set with the ``setReturnPath()`` method of the message. You can only have one ``Return-Path:`` and it must not include a personal name. Bounce notifications will be sent to this address:: $message->setReturnPath('bounces@address.tld'); Signed/Encrypted Message ------------------------ To increase the integrity/security of a message it is possible to sign and/or encrypt an message using one or multiple signers. S/MIME ~~~~~~ S/MIME can sign and/or encrypt a message using the OpenSSL extension. When signing a message, the signer creates a signature of the entire content of the message (including attachments). The certificate and private key must be PEM encoded, and can be either created using for example OpenSSL or obtained at an official Certificate Authority (CA). **The recipient must have the CA certificate in the list of trusted issuers in order to verify the signature.** **Make sure the certificate supports emailProtection.** When using OpenSSL this can done by the including the *-addtrust emailProtection* parameter when creating the certificate:: $message = new Swift_Message(); $smimeSigner = new Swift_Signers_SMimeSigner(); $smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem'); $message->attachSigner($smimeSigner); When the private key is secured using a passphrase use the following instead:: $message = new Swift_Message(); $smimeSigner = new Swift_Signers_SMimeSigner(); $smimeSigner->setSignCertificate('/path/to/certificate.pem', ['/path/to/private-key.pem', 'passphrase']); $message->attachSigner($smimeSigner); By default the signature is added as attachment, making the message still readable for mailing agents not supporting signed messages. Storing the message as binary is also possible but not recommended:: $smimeSigner->setSignCertificate('/path/to/certificate.pem', '/path/to/private-key.pem', PKCS7_BINARY); When encrypting the message (also known as enveloping), the entire message (including attachments) is encrypted using a certificate, and the recipient can then decrypt the message using corresponding private key. Encrypting ensures nobody can read the contents of the message without the private key. Normally the recipient provides a certificate for encrypting and keeping the decryption key private. Using both signing and encrypting is also possible:: $message = new Swift_Message(); $smimeSigner = new Swift_Signers_SMimeSigner(); $smimeSigner->setSignCertificate('/path/to/sign-certificate.pem', '/path/to/private-key.pem'); $smimeSigner->setEncryptCertificate('/path/to/encrypt-certificate.pem'); $message->attachSigner($smimeSigner); The used encryption cipher can be set as the second parameter of setEncryptCertificate() See https://secure.php.net/manual/openssl.ciphers for a list of supported ciphers. By default the message is first signed and then encrypted, this can be changed by adding:: $smimeSigner->setSignThenEncrypt(false); **Changing this is not recommended as most mail agents don't support this none-standard way.** Only when having trouble with sign then encrypt method, this should be changed. Requesting a Read Receipt ------------------------- It is possible to request a read-receipt to be sent to an address when the email is opened. To request a read receipt set the address with ``setReadReceiptTo()``:: $message->setReadReceiptTo('your@address.tld'); When the email is opened, if the mail client supports it a notification will be sent to this address. .. note:: Read receipts won't work for the majority of recipients since many mail clients auto-disable them. Those clients that will send a read receipt will make the user aware that one has been requested. Setting the Character Set ------------------------- The character set of the message (and its MIME parts) is set with the ``setCharset()`` method. You can also change the global default of UTF-8 by working with the ``Swift_Preferences`` class. Swift Mailer will default to the UTF-8 character set unless otherwise overridden. UTF-8 will work in most instances since it includes all of the standard US keyboard characters in addition to most international characters. It is absolutely vital however that you know what character set your message (or it's MIME parts) are written in otherwise your message may be received completely garbled. There are two places in Swift Mailer where you can change the character set: * In the ``Swift_Preferences`` class * On each individual message and/or MIME part To set the character set of your Message: * Change the global UTF-8 setting by calling ``Swift_Preferences::setCharset()``; or * Call the ``setCharset()`` method on the message or the MIME part:: // Approach 1: Change the global setting (suggested) Swift_Preferences::getInstance()->setCharset('iso-8859-2'); // Approach 2: Call the setCharset() method of the message $message = (new Swift_Message()) ->setCharset('iso-8859-2'); // Approach 3: Specify the charset when setting the body $message->setBody('My body', 'text/html', 'iso-8859-2'); // Approach 4: Specify the charset for each part added $message->addPart('My part', 'text/plain', 'iso-8859-2'); Setting the Encoding -------------------- The body of each MIME part needs to be encoded. Binary attachments are encoded in base64 using the ``Swift_Mime_ContentEncoder_Base64ContentEncoder``. Text parts are traditionally encoded in quoted-printable using ``Swift_Mime_ContentEncoder_QpContentEncoder`` or ``Swift_Mime_ContentEncoder_NativeQpContentEncoder``. The encoder of the message or MIME part is set with the ``setEncoder()`` method. Quoted-printable is the safe choice, because it converts 8-bit text as 7-bit. Most modern SMTP servers support 8-bit text. This is advertised via the 8BITMIME SMTP extension. If your outbound SMTP server supports this SMTP extension, and it supports downgrading the message (e.g converting to quoted-printable on the fly) when delivering to a downstream server that does not support the extension, you may wish to use ``Swift_Mime_ContentEncoder_PlainContentEncoder`` in ``8bit`` mode instead. This has the advantage that the source data is slightly more readable and compact, especially for non-Western languages. $eightBitMime = new Swift_Transport_Esmtp_EightBitMimeHandler(); $transport->setExtensionHandlers([$eightBitMime]); $plainEncoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit'); $message->setEncoder($plainEncoder); Setting the Line Length ----------------------- The length of lines in a message can be changed by using the ``setMaxLineLength()`` method on the message:: $message->setMaxLineLength(1000); Swift Mailer defaults to using 78 characters per line in a message. This is done for historical reasons and so that the message can be easily viewed in plain-text terminals Lines that are longer than the line length specified will be wrapped between words. .. note:: You should never set a maximum length longer than 1000 characters according to RFC 2822. Doing so could have unspecified side-effects such as truncating parts of your message when it is transported between SMTP servers. Setting the Message Priority ---------------------------- You can change the priority of the message with ``setPriority()``. Setting the priority will not change the way your email is sent -- it is purely an indicative setting for the recipient:: // Indicate "High" priority $message->setPriority(2); The priority of a message is an indication to the recipient what significance it has. Swift Mailer allows you to set the priority by calling the ``setPriority`` method. This method takes an integer value between 1 and 5: * ``Swift_Mime_SimpleMessage::PRIORITY_HIGHEST``: 1 * ``Swift_Mime_SimpleMessage::PRIORITY_HIGH``: 2 * ``Swift_Mime_SimpleMessage::PRIORITY_NORMAL``: 3 * ``Swift_Mime_SimpleMessage::PRIORITY_LOW``: 4 * ``Swift_Mime_SimpleMessage::PRIORITY_LOWEST``: 5 :: // Or use the constant to be more explicit $message->setPriority(Swift_Mime_SimpleMessage::PRIORITY_HIGH); swiftmailer/doc/plugins.rst 0000777 00000031505 14710744267 0012101 0 ustar 00 Plugins ======= Plugins exist to extend, or modify the behaviour of Swift Mailer. They respond to Events that are fired within the Transports during sending. There are a number of Plugins provided as part of the base Swift Mailer package and they all follow a common interface to respond to Events fired within the library. Interfaces are provided to "listen" to each type of Event fired and to act as desired when a listened-to Event occurs. Although several plugins are provided with Swift Mailer out-of-the-box, the Events system has been specifically designed to make it easy for experienced object-oriented developers to write their own plugins in order to achieve goals that may not be possible with the base library. AntiFlood Plugin ---------------- Many SMTP servers have limits on the number of messages that may be sent during any single SMTP connection. The AntiFlood plugin provides a way to stay within this limit while still managing a large number of emails. A typical limit for a single connection is 100 emails. If the server you connect to imposes such a limit, it expects you to disconnect after that number of emails has been sent. You could manage this manually within a loop, but the AntiFlood plugin provides the necessary wrapper code so that you don't need to worry about this logic. Regardless of limits imposed by the server, it's usually a good idea to be conservative with the resources of the SMTP server. Sending will become sluggish if the server is being over-used so using the AntiFlood plugin will not be a bad idea even if no limits exist. The AntiFlood plugin's logic is basically to disconnect and the immediately re-connect with the SMTP server every X number of emails sent, where X is a number you specify to the plugin. You can also specify a time period in seconds that Swift Mailer should pause for between the disconnect/re-connect process. It's a good idea to pause for a short time (say 30 seconds every 100 emails) simply to give the SMTP server a chance to process its queue and recover some resources. Using the AntiFlood Plugin ~~~~~~~~~~~~~~~~~~~~~~~~~~ The AntiFlood Plugin -- like all plugins -- is added with the Mailer class's ``registerPlugin()`` method. It takes two constructor parameters: the number of emails to pause after, and optionally the number of seconds to pause for. When Swift Mailer sends messages it will count the number of messages that have been sent since the last re-connect. Once the number hits your specified threshold it will disconnect and re-connect, optionally pausing for a specified amount of time:: // Create the Mailer using any Transport $mailer = new Swift_Mailer( new Swift_SmtpTransport('smtp.example.org', 25) ); // Use AntiFlood to re-connect after 100 emails $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100)); // And specify a time in seconds to pause for (30 secs) $mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30)); // Continue sending as normal for ($lotsOfRecipients as $recipient) { ... $mailer->send( ... ); } Throttler Plugin ---------------- If your SMTP server has restrictions in place to limit the rate at which you send emails, then your code will need to be aware of this rate-limiting. The Throttler plugin makes Swift Mailer run at a rate-limited speed. Many shared hosts don't open their SMTP servers as a free-for-all. Usually they have policies in place (probably to discourage spammers) that only allow you to send a fixed number of emails per-hour/day. The Throttler plugin supports two modes of rate-limiting and with each, you will need to do that math to figure out the values you want. The plugin can limit based on the number of emails per minute, or the number of bytes-transferred per-minute. Using the Throttler Plugin ~~~~~~~~~~~~~~~~~~~~~~~~~~ The Throttler Plugin -- like all plugins -- is added with the Mailer class' ``registerPlugin()`` method. It has two required constructor parameters that tell it how to do its rate-limiting. When Swift Mailer sends messages it will keep track of the rate at which sending messages is occurring. If it realises that sending is happening too fast, it will cause your program to ``sleep()`` for enough time to average out the rate:: // Create the Mailer using any Transport $mailer = new Swift_Mailer( new Swift_SmtpTransport('smtp.example.org', 25) ); // Rate limit to 100 emails per-minute $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( 100, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE )); // Rate limit to 10MB per-minute $mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin( 1024 * 1024 * 10, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE )); // Continue sending as normal for ($lotsOfRecipients as $recipient) { ... $mailer->send( ... ); } Logger Plugin ------------- The Logger plugins helps with debugging during the process of sending. It can help to identify why an SMTP server is rejecting addresses, or any other hard-to-find problems that may arise. The Logger plugin comes in two parts. There's the plugin itself, along with one of a number of possible Loggers that you may choose to use. For example, the logger may output messages directly in realtime, or it may capture messages in an array. One other notable feature is the way in which the Logger plugin changes Exception messages. If Exceptions are being thrown but the error message does not provide conclusive information as to the source of the problem (such as an ambiguous SMTP error) the Logger plugin includes the entire SMTP transcript in the error message so that debugging becomes a simpler task. There are a few available Loggers included with Swift Mailer, but writing your own implementation is incredibly simple and is achieved by creating a short class that implements the ``Swift_Plugins_Logger`` interface. * ``Swift_Plugins_Loggers_ArrayLogger``: Keeps a collection of log messages inside an array. The array content can be cleared or dumped out to the screen. * ``Swift_Plugins_Loggers_EchoLogger``: Prints output to the screen in realtime. Handy for very rudimentary debug output. Using the Logger Plugin ~~~~~~~~~~~~~~~~~~~~~~~ The Logger Plugin -- like all plugins -- is added with the Mailer class' ``registerPlugin()`` method. It accepts an instance of ``Swift_Plugins_Logger`` in its constructor. When Swift Mailer sends messages it will keep a log of all the interactions with the underlying Transport being used. Depending upon the Logger that has been used the behaviour will differ, but all implementations offer a way to get the contents of the log:: // Create the Mailer using any Transport $mailer = new Swift_Mailer( new Swift_SmtpTransport('smtp.example.org', 25) ); // To use the ArrayLogger $logger = new Swift_Plugins_Loggers_ArrayLogger(); $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger)); // Or to use the Echo Logger $logger = new Swift_Plugins_Loggers_EchoLogger(); $mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger)); // Continue sending as normal for ($lotsOfRecipients as $recipient) { ... $mailer->send( ... ); } // Dump the log contents // NOTE: The EchoLogger dumps in realtime so dump() does nothing for it echo $logger->dump(); Decorator Plugin ---------------- Often there's a need to send the same message to multiple recipients, but with tiny variations such as the recipient's name being used inside the message body. The Decorator plugin aims to provide a solution for allowing these small differences. The decorator plugin works by intercepting the sending process of Swift Mailer, reading the email address in the To: field and then looking up a set of replacements for a template. While the use of this plugin is simple, it is probably the most commonly misunderstood plugin due to the way in which it works. The typical mistake users make is to try registering the plugin multiple times (once for each recipient) -- inside a loop for example. This is incorrect. The Decorator plugin should be registered just once, but containing the list of all recipients prior to sending. It will use this list of recipients to find the required replacements during sending. Using the Decorator Plugin ~~~~~~~~~~~~~~~~~~~~~~~~~~ To use the Decorator plugin, simply create an associative array of replacements based on email addresses and then use the mailer's ``registerPlugin()`` method to add the plugin. First create an associative array of replacements based on the email addresses you'll be sending the message to. .. note:: The replacements array becomes a 2-dimensional array whose keys are the email addresses and whose values are an associative array of replacements for that email address. The curly braces used in this example can be any type of syntax you choose, provided they match the placeholders in your email template:: $replacements = []; foreach ($users as $user) { $replacements[$user['email']] = [ '{username}'=>$user['username'], '{resetcode}'=>$user['resetcode'] ]; } Now create an instance of the Decorator plugin using this array of replacements and then register it with the Mailer. Do this only once! :: $decorator = new Swift_Plugins_DecoratorPlugin($replacements); $mailer->registerPlugin($decorator); When you create your message, replace elements in the body (and/or the subject line) with your placeholders:: $message = (new Swift_Message()) ->setSubject('Important notice for {username}') ->setBody( "Hello {username}, you requested to reset your password.\n" . "Please visit https://example.com/pwreset and use the reset code {resetcode} to set a new password." ) ; foreach ($users as $user) { $message->addTo($user['email']); } When you send this message to each of your recipients listed in your ``$replacements`` array they will receive a message customized for just themselves. For example, the message used above when received may appear like this to one user: .. code-block:: text Subject: Important notice for smilingsunshine2009 Hello smilingsunshine2009, you requested to reset your password. Please visit https://example.com/pwreset and use the reset code 183457 to set a new password. While another use may receive the message as: .. code-block:: text Subject: Important notice for billy-bo-bob Hello billy-bo-bob, you requested to reset your password. Please visit https://example.com/pwreset and use the reset code 539127 to set a new password. While the decorator plugin provides a means to solve this problem, there are various ways you could tackle this problem without the need for a plugin. We're trying to come up with a better way ourselves and while we have several (obvious) ideas we don't quite have the perfect solution to go ahead and implement it. Watch this space. Providing Your Own Replacements Lookup for the Decorator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Filling an array with replacements may not be the best solution for providing replacement information to the decorator. If you have a more elegant algorithm that performs replacement lookups on-the-fly you may provide your own implementation. Providing your own replacements lookup implementation for the Decorator is simply a matter of passing an instance of ``Swift_Plugins_Decorator_Replacements`` to the decorator plugin's constructor, rather than passing in an array. The Replacements interface is very simple to implement since it has just one method: ``getReplacementsFor($address)``. Imagine you want to look up replacements from a database on-the-fly, you might provide an implementation that does this. You need to create a small class:: class DbReplacements implements Swift_Plugins_Decorator_Replacements { public function getReplacementsFor($address) { global $db; // Your PDO instance with a connection to your database $query = $db->prepare( "SELECT * FROM `users` WHERE `email` = ?" ); $query->execute([$address]); if ($row = $query->fetch(PDO::FETCH_ASSOC)) { return [ '{username}'=>$row['username'], '{resetcode}'=>$row['resetcode'] ]; } } } Now all you need to do is pass an instance of your class into the Decorator plugin's constructor instead of passing an array:: $decorator = new Swift_Plugins_DecoratorPlugin(new DbReplacements()); $mailer->registerPlugin($decorator); For each message sent, the plugin will call your class' ``getReplacementsFor()`` method to find the array of replacements it needs. .. note:: If your lookup algorithm is case sensitive, you should transform the ``$address`` argument as appropriate -- for example by passing it through ``strtolower()``. swiftmailer/doc/sending.rst 0000777 00000042070 14710744267 0012046 0 ustar 00 Sending Messages ================ Quick Reference for Sending a Message ------------------------------------- Sending a message is very straightforward. You create a Transport, use it to create the Mailer, then you use the Mailer to send the message. When using ``send()`` the message will be sent just like it would be sent if you used your mail client. An integer is returned which includes the number of successful recipients. If none of the recipients could be sent to then zero will be returned, which equates to a boolean ``false``. If you set two ``To:`` recipients and three ``Bcc:`` recipients in the message and all of the recipients are delivered to successfully then the value 5 will be returned:: // Create the Transport $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) ->setUsername('your username') ->setPassword('your password') ; /* You could alternatively use a different transport such as Sendmail: // Sendmail $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs'); */ // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); // Create a message $message = (new Swift_Message('Wonderful Subject')) ->setFrom(['john@doe.com' => 'John Doe']) ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) ->setBody('Here is the message itself') ; // Send the message $result = $mailer->send($message); Transport Types ~~~~~~~~~~~~~~~ Transports are the classes in Swift Mailer that are responsible for communicating with a service in order to deliver a Message. There are several types of Transport in Swift Mailer, all of which implement the ``Swift_Transport`` interface:: * ``Swift_SmtpTransport``: Sends messages over SMTP; Supports Authentication; Supports Encryption. Very portable; Pleasingly predictable results; Provides good feedback; * ``Swift_SendmailTransport``: Communicates with a locally installed ``sendmail`` executable (Linux/UNIX). Quick time-to-run; Provides less-accurate feedback than SMTP; Requires ``sendmail`` installation; * ``Swift_LoadBalancedTransport``: Cycles through a collection of the other Transports to manage load-reduction. Provides graceful fallback if one Transport fails (e.g. an SMTP server is down); Keeps the load on remote services down by spreading the work; * ``Swift_FailoverTransport``: Works in conjunction with a collection of the other Transports to provide high-availability. Provides graceful fallback if one Transport fails (e.g. an SMTP server is down). The SMTP Transport .................. The SMTP Transport sends messages over the (standardized) Simple Message Transfer Protocol. It can deal with encryption and authentication. The SMTP Transport, ``Swift_SmtpTransport`` is without doubt the most commonly used Transport because it will work on 99% of web servers (I just made that number up, but you get the idea). All the server needs is the ability to connect to a remote (or even local) SMTP server on the correct port number (usually 25). SMTP servers often require users to authenticate with a username and password before any mail can be sent to other domains. This is easily achieved using Swift Mailer with the SMTP Transport. SMTP is a protocol -- in other words it's a "way" of communicating a job to be done (i.e. sending a message). The SMTP protocol is the fundamental basis on which messages are delivered all over the internet 7 days a week, 365 days a year. For this reason it's the most "direct" method of sending messages you can use and it's the one that will give you the most power and feedback (such as delivery failures) when using Swift Mailer. Because SMTP is generally run as a remote service (i.e. you connect to it over the network/internet) it's extremely portable from server-to-server. You can easily store the SMTP server address and port number in a configuration file within your application and adjust the settings accordingly if the code is moved or if the SMTP server is changed. Some SMTP servers -- Google for example -- use encryption for security reasons. Swift Mailer supports using both ``ssl`` (SMTPS = SMTP over TLS) and ``tls`` (SMTP with STARTTLS) encryption settings. Using the SMTP Transport ^^^^^^^^^^^^^^^^^^^^^^^^ The SMTP Transport is easy to use. Most configuration options can be set with the constructor. To use the SMTP Transport you need to know which SMTP server your code needs to connect to. Ask your web host if you're not sure. Lots of people ask me who to connect to -- I really can't answer that since it's a setting that's extremely specific to your hosting environment. A connection to the SMTP server will be established upon the first call to ``send()``:: // Create the Transport $transport = new Swift_SmtpTransport('smtp.example.org', 25); // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); /* It's also possible to use multiple method calls $transport = (new Swift_SmtpTransport()) ->setHost('smtp.example.org') ->setPort(25) ; */ Encrypted SMTP ^^^^^^^^^^^^^^ You can use ``ssl`` (SMTPS) or ``tls`` (STARTTLS) encryption with the SMTP Transport by specifying it as a parameter or with a method call:: // Create the Transport // Option #1: SMTPS = SMTP over TLS (always encrypted): $transport = new Swift_SmtpTransport('smtp.example.org', 587, 'ssl'); // Option #2: SMTP with STARTTLS (best effort encryption): $transport = new Swift_SmtpTransport('smtp.example.org', 587, 'tls'); // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); A connection to the SMTP server will be established upon the first call to ``send()``. The connection will be initiated with the correct encryption settings. .. note:: For SMTPS or STARTTLS encryption to work your PHP installation must have appropriate OpenSSL transports wrappers. You can check if "tls" and/or "ssl" are present in your PHP installation by using the PHP function ``stream_get_transports()``. .. note:: If you are using Mailcatcher_, make sure you do not set the encryption for the ``Swift_SmtpTransport``, since Mailcatcher does not support encryption. .. note:: When in doubt, try ``ssl`` first for higher security, since the communication is always encrypted. .. note:: Usually, port 587 or 465 is used for encrypted SMTP. Check the documentation of your mail provider. SMTP with a Username and Password ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Some servers require authentication. You can provide a username and password with ``setUsername()`` and ``setPassword()`` methods:: // Create the Transport the call setUsername() and setPassword() $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) ->setUsername('username') ->setPassword('password') ; // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); Your username and password will be used to authenticate upon first connect when ``send()`` are first used on the Mailer. If authentication fails, an Exception of type ``Swift_TransportException`` will be thrown. .. note:: If you need to know early whether or not authentication has failed and an Exception is going to be thrown, call the ``start()`` method on the created Transport. The Sendmail Transport ...................... The Sendmail Transport sends messages by communicating with a locally installed MTA -- such as ``sendmail``. The Sendmail Transport, ``Swift_SendmailTransport`` does not directly connect to any remote services. It is designed for Linux servers that have ``sendmail`` installed. The Transport starts a local ``sendmail`` process and sends messages to it. Usually the ``sendmail`` process will respond quickly as it spools your messages to disk before sending them. The Transport is named the Sendmail Transport for historical reasons (``sendmail`` was the "standard" UNIX tool for sending e-mail for years). It will send messages using other transfer agents such as Exim or Postfix despite its name, provided they have the relevant sendmail wrappers so that they can be started with the correct command-line flags. It's a common misconception that because the Sendmail Transport returns a result very quickly it must therefore deliver messages to recipients quickly -- this is not true. It's not slow by any means, but it's certainly not faster than SMTP when it comes to getting messages to the intended recipients. This is because sendmail itself sends the messages over SMTP once they have been quickly spooled to disk. The Sendmail Transport has the potential to be just as smart of the SMTP Transport when it comes to notifying Swift Mailer about which recipients were rejected, but in reality the majority of locally installed ``sendmail`` instances are not configured well enough to provide any useful feedback. As such Swift Mailer may report successful deliveries where they did in fact fail before they even left your server. You can run the Sendmail Transport in two different modes specified by command line flags: * "``-bs``" runs in SMTP mode so theoretically it will act like the SMTP Transport * "``-t``" runs in piped mode with no feedback, but theoretically faster, though not advised You can think of the Sendmail Transport as a sort of asynchronous SMTP Transport -- though if you have problems with delivery failures you should try using the SMTP Transport instead. Swift Mailer isn't doing the work here, it's simply passing the work to somebody else (i.e. ``sendmail``). Using the Sendmail Transport ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To use the Sendmail Transport you simply need to call ``new Swift_SendmailTransport()`` with the command as a parameter. To use the Sendmail Transport you need to know where ``sendmail`` or another MTA exists on the server. Swift Mailer uses a default value of ``/usr/sbin/sendmail``, which should work on most systems. You specify the entire command as a parameter (i.e. including the command line flags). Swift Mailer supports operational modes of "``-bs``" (default) and "``-t``". .. note:: If you run sendmail in "``-t``" mode you will get no feedback as to whether or not sending has succeeded. Use "``-bs``" unless you have a reason not to. A sendmail process will be started upon the first call to ``send()``. If the process cannot be started successfully an Exception of type ``Swift_TransportException`` will be thrown:: // Create the Transport $transport = new Swift_SendmailTransport('/usr/sbin/exim -bs'); // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); Available Methods for Sending Messages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Mailer class offers one method for sending Messages -- ``send()``. When a message is sent in Swift Mailer, the Mailer class communicates with whichever Transport class you have chosen to use. Each recipient in the message should either be accepted or rejected by the Transport. For example, if the domain name on the email address is not reachable the SMTP Transport may reject the address because it cannot process it. ``send()`` will return an integer indicating the number of accepted recipients. .. note:: It's possible to find out which recipients were rejected -- we'll cover that later in this chapter. Using the ``send()`` Method ........................... The ``send()`` method of the ``Swift_Mailer`` class sends a message using exactly the same logic as your Desktop mail client would use. Just pass it a Message and get a result. The message will be sent just like it would be sent if you used your mail client. An integer is returned which includes the number of successful recipients. If none of the recipients could be sent to then zero will be returned, which equates to a boolean ``false``. If you set two ``To:`` recipients and three ``Bcc:`` recipients in the message and all of the recipients are delivered to successfully then the value 5 will be returned:: // Create the Transport $transport = new Swift_SmtpTransport('localhost', 25); // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); // Create a message $message = (new Swift_Message('Wonderful Subject')) ->setFrom(['john@doe.com' => 'John Doe']) ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) ->setBody('Here is the message itself') ; // Send the message $numSent = $mailer->send($message); printf("Sent %d messages\n", $numSent); /* Note that often that only the boolean equivalent of the return value is of concern (zero indicates FALSE) if ($mailer->send($message)) { echo "Sent\n"; } else { echo "Failed\n"; } */ Sending Emails in Batch ....................... If you want to send a separate message to each recipient so that only their own address shows up in the ``To:`` field, follow the following recipe: * Create a Transport from one of the provided Transports -- ``Swift_SmtpTransport``, ``Swift_SendmailTransport``, or one of the aggregate Transports. * Create an instance of the ``Swift_Mailer`` class, using the Transport as it's constructor parameter. * Create a Message. * Iterate over the recipients and send message via the ``send()`` method on the Mailer object. Each recipient of the messages receives a different copy with only their own email address on the ``To:`` field. Make sure to add only valid email addresses as recipients. If you try to add an invalid email address with ``setTo()``, ``setCc()`` or ``setBcc()``, Swift Mailer will throw a ``Swift_RfcComplianceException``. If you add recipients automatically based on a data source that may contain invalid email addresses, you can prevent possible exceptions by validating the addresses using ``Egulias\EmailValidator\EmailValidator`` (a dependency that is installed with Swift Mailer) and only adding addresses that validate. Another way would be to wrap your ``setTo()``, ``setCc()`` and ``setBcc()`` calls in a try-catch block and handle the ``Swift_RfcComplianceException`` in the catch block. Handling invalid addresses properly is especially important when sending emails in large batches since a single invalid address might cause an unhandled exception and stop the execution or your script early. .. note:: In the following example, two emails are sent. One to each of ``receiver@domain.org`` and ``other@domain.org``. These recipients will not be aware of each other:: // Create the Transport $transport = new Swift_SmtpTransport('localhost', 25); // Create the Mailer using your created Transport $mailer = new Swift_Mailer($transport); // Create a message $message = (new Swift_Message('Wonderful Subject')) ->setFrom(['john@doe.com' => 'John Doe']) ->setBody('Here is the message itself') ; // Send the message $failedRecipients = []; $numSent = 0; $to = ['receiver@domain.org', 'other@domain.org' => 'A name']; foreach ($to as $address => $name) { if (is_int($address)) { $message->setTo($name); } else { $message->setTo([$address => $name]); } $numSent += $mailer->send($message, $failedRecipients); } printf("Sent %d messages\n", $numSent); Finding out Rejected Addresses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's possible to get a list of addresses that were rejected by the Transport by using a by-reference parameter to ``send()``. As Swift Mailer attempts to send the message to each address given to it, if a recipient is rejected it will be added to the array. You can pass an existing array, otherwise one will be created by-reference. Collecting the list of recipients that were rejected can be useful in circumstances where you need to "prune" a mailing list for example when some addresses cannot be delivered to. Getting Failures By-reference ............................. Collecting delivery failures by-reference with the ``send()`` method is as simple as passing a variable name to the method call:: $mailer = new Swift_Mailer( ... ); $message = (new Swift_Message( ... )) ->setFrom( ... ) ->setTo([ 'receiver@bad-domain.org' => 'Receiver Name', 'other@domain.org' => 'A name', 'other-receiver@bad-domain.org' => 'Other Name' )) ->setBody( ... ) ; // Pass a variable name to the send() method if (!$mailer->send($message, $failures)) { echo "Failures:"; print_r($failures); } /* Failures: Array ( 0 => receiver@bad-domain.org, 1 => other-receiver@bad-domain.org ) */ If the Transport rejects any of the recipients, the culprit addresses will be added to the array provided by-reference. .. note:: If the variable name does not yet exist, it will be initialized as an empty array and then failures will be added to that array. If the variable already exists it will be type-cast to an array and failures will be added to it. .. _Mailcatcher: https://mailcatcher.me/ swiftmailer/doc/headers.rst 0000777 00000050004 14710744267 0012026 0 ustar 00 Message Headers =============== Sometimes you'll want to add your own headers to a message or modify/remove headers that are already present. You work with the message's HeaderSet to do this. Header Basics ------------- All MIME entities in Swift Mailer -- including the message itself -- store their headers in a single object called a HeaderSet. This HeaderSet is retrieved with the ``getHeaders()`` method. As mentioned in the previous chapter, everything that forms a part of a message in Swift Mailer is a MIME entity that is represented by an instance of ``Swift_Mime_SimpleMimeEntity``. This includes -- most notably -- the message object itself, attachments, MIME parts and embedded images. Each of these MIME entities consists of a body and a set of headers that describe the body. For all of the "standard" headers in these MIME entities, such as the ``Content-Type``, there are named methods for working with them, such as ``setContentType()`` and ``getContentType()``. This is because headers are a moderately complex area of the library. Each header has a slightly different required structure that it must meet in order to comply with the standards that govern email (and that are checked by spam blockers etc). You fetch the HeaderSet from a MIME entity like so:: $message = new Swift_Message(); // Fetch the HeaderSet from a Message object $headers = $message->getHeaders(); $attachment = Swift_Attachment::fromPath('document.pdf'); // Fetch the HeaderSet from an attachment object $headers = $attachment->getHeaders(); The job of the HeaderSet is to contain and manage instances of Header objects. Depending upon the MIME entity the HeaderSet came from, the contents of the HeaderSet will be different, since an attachment for example has a different set of headers to those in a message. You can find out what the HeaderSet contains with a quick loop, dumping out the names of the headers:: foreach ($headers->getAll() as $header) { printf("%s<br />\n", $header->getFieldName()); } /* Content-Transfer-Encoding Content-Type MIME-Version Date Message-ID From Subject To */ You can also dump out the rendered HeaderSet by calling its ``toString()`` method:: echo $headers->toString(); /* Message-ID: <1234869991.499a9ee7f1d5e@swift.generated> Date: Tue, 17 Feb 2009 22:26:31 +1100 Subject: Awesome subject! From: sender@example.org To: recipient@example.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable */ Where the complexity comes in is when you want to modify an existing header. This complexity comes from the fact that each header can be of a slightly different type (such as a Date header, or a header that contains email addresses, or a header that has key-value parameters on it!). Each header in the HeaderSet is an instance of ``Swift_Mime_Header``. They all have common functionality, but knowing exactly what type of header you're working with will allow you a little more control. You can determine the type of header by comparing the return value of its ``getFieldType()`` method with the constants ``TYPE_TEXT``, ``TYPE_PARAMETERIZED``, ``TYPE_DATE``, ``TYPE_MAILBOX``, ``TYPE_ID`` and ``TYPE_PATH`` which are defined in ``Swift_Mime_Header``:: foreach ($headers->getAll() as $header) { switch ($header->getFieldType()) { case Swift_Mime_Header::TYPE_TEXT: $type = 'text'; break; case Swift_Mime_Header::TYPE_PARAMETERIZED: $type = 'parameterized'; break; case Swift_Mime_Header::TYPE_MAILBOX: $type = 'mailbox'; break; case Swift_Mime_Header::TYPE_DATE: $type = 'date'; break; case Swift_Mime_Header::TYPE_ID: $type = 'ID'; break; case Swift_Mime_Header::TYPE_PATH: $type = 'path'; break; } printf("%s: is a %s header<br />\n", $header->getFieldName(), $type); } /* Content-Transfer-Encoding: is a text header Content-Type: is a parameterized header MIME-Version: is a text header Date: is a date header Message-ID: is a ID header From: is a mailbox header Subject: is a text header To: is a mailbox header */ Headers can be removed from the set, modified within the set, or added to the set. The following sections show you how to work with the HeaderSet and explain the details of each implementation of ``Swift_Mime_Header`` that may exist within the HeaderSet. Header Types ------------ Because all headers are modeled on different data (dates, addresses, text!) there are different types of Header in Swift Mailer. Swift Mailer attempts to categorize all possible MIME headers into more general groups, defined by a small number of classes. Text Headers ~~~~~~~~~~~~ Text headers are the simplest type of Header. They contain textual information with no special information included within it -- for example the Subject header in a message. There's nothing particularly interesting about a text header, though it is probably the one you'd opt to use if you need to add a custom header to a message. It represents text just like you'd think it does. If the text contains characters that are not permitted in a message header (such as new lines, or non-ascii characters) then the header takes care of encoding the text so that it can be used. No header -- including text headers -- in Swift Mailer is vulnerable to header-injection attacks. Swift Mailer breaks any attempt at header injection by encoding the dangerous data into a non-dangerous form. It's easy to add a new text header to a HeaderSet. You do this by calling the HeaderSet's ``addTextHeader()`` method:: $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addTextHeader('Your-Header-Name', 'the header value'); Changing the value of an existing text header is done by calling it's ``setValue()`` method:: $subject = $message->getHeaders()->get('Subject'); $subject->setValue('new subject'); When output via ``toString()``, a text header produces something like the following:: $subject = $message->getHeaders()->get('Subject'); $subject->setValue('amazing subject line'); echo $subject->toString(); /* Subject: amazing subject line */ If the header contains any characters that are outside of the US-ASCII range however, they will be encoded. This is nothing to be concerned about since mail clients will decode them back:: $subject = $message->getHeaders()->get('Subject'); $subject->setValue('contains – dash'); echo $subject->toString(); /* Subject: contains =?utf-8?Q?=E2=80=93?= dash */ Parameterized Headers ~~~~~~~~~~~~~~~~~~~~~ Parameterized headers are text headers that contain key-value parameters following the textual content. The Content-Type header of a message is a parameterized header since it contains charset information after the content type. The parameterized header type is a special type of text header. It extends the text header by allowing additional information to follow it. All of the methods from text headers are available in addition to the methods described here. Adding a parameterized header to a HeaderSet is done by using the ``addParameterizedHeader()`` method which takes a text value like ``addTextHeader()`` but it also accepts an associative array of key-value parameters:: $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addParameterizedHeader( 'Header-Name', 'header value', ['foo' => 'bar'] ); To change the text value of the header, call it's ``setValue()`` method just as you do with text headers. To change the parameters in the header, call the header's ``setParameters()`` method or the ``setParameter()`` method (note the pluralization):: $type = $message->getHeaders()->get('Content-Type'); // setParameters() takes an associative array $type->setParameters([ 'name' => 'file.txt', 'charset' => 'iso-8859-1' ]); // setParameter() takes two args for $key and $value $type->setParameter('charset', 'iso-8859-1'); When output via ``toString()``, a parameterized header produces something like the following:: $type = $message->getHeaders()->get('Content-Type'); $type->setValue('text/html'); $type->setParameter('charset', 'utf-8'); echo $type->toString(); /* Content-Type: text/html; charset=utf-8 */ If the header contains any characters that are outside of the US-ASCII range however, they will be encoded, just like they are for text headers. This is nothing to be concerned about since mail clients will decode them back. Likewise, if the parameters contain any non-ascii characters they will be encoded so that they can be transmitted safely:: $attachment = new Swift_Attachment(); $disp = $attachment->getHeaders()->get('Content-Disposition'); $disp->setValue('attachment'); $disp->setParameter('filename', 'report–may.pdf'); echo $disp->toString(); /* Content-Disposition: attachment; filename*=utf-8''report%E2%80%93may.pdf */ Date Headers ~~~~~~~~~~~~ Date headers contains an RFC 2822 formatted date (i.e. what PHP's ``date('r')`` returns). They are used anywhere a date or time is needed to be presented as a message header. The data on which a date header is modeled as a DateTimeImmutable object. The object is used to create a correctly structured RFC 2822 formatted date with timezone such as ``Tue, 17 Feb 2009 22:26:31 +1100``. The obvious place this header type is used is in the ``Date:`` header of the message itself. It's easy to add a new date header to a HeaderSet. You do this by calling the HeaderSet's ``addDateHeader()`` method:: $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addDateHeader('Your-Header', new DateTimeImmutable('3 days ago')); Changing the value of an existing date header is done by calling it's ``setDateTime()`` method:: $date = $message->getHeaders()->get('Date'); $date->setDateTime(new DateTimeImmutable()); When output via ``toString()``, a date header produces something like the following:: $date = $message->getHeaders()->get('Date'); echo $date->toString(); /* Date: Wed, 18 Feb 2009 13:35:02 +1100 */ Mailbox (e-mail address) Headers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mailbox headers contain one or more email addresses, possibly with personalized names attached to them. The data on which they are modeled is represented by an associative array of email addresses and names. Mailbox headers are probably the most complex header type to understand in Swift Mailer because they accept their input as an array which can take various forms, as described in the previous chapter. All of the headers that contain e-mail addresses in a message -- with the exception of ``Return-Path:`` which has a stricter syntax -- use this header type. That is, ``To:``, ``From:`` etc. You add a new mailbox header to a HeaderSet by calling the HeaderSet's ``addMailboxHeader()`` method:: $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addMailboxHeader('Your-Header-Name', [ 'person1@example.org' => 'Person Name One', 'person2@example.org', 'person3@example.org', 'person4@example.org' => 'Another named person' ]); Changing the value of an existing mailbox header is done by calling it's ``setNameAddresses()`` method:: $to = $message->getHeaders()->get('To'); $to->setNameAddresses([ 'joe@example.org' => 'Joe Bloggs', 'john@example.org' => 'John Doe', 'no-name@example.org' ]); If you don't wish to concern yourself with the complicated accepted input formats accepted by ``setNameAddresses()`` as described in the previous chapter and you only want to set one or more addresses (not names) then you can just use the ``setAddresses()`` method instead:: $to = $message->getHeaders()->get('To'); $to->setAddresses([ 'joe@example.org', 'john@example.org', 'no-name@example.org' ]); .. note:: Both methods will accept the above input format in practice. If all you want to do is set a single address in the header, you can use a string as the input parameter to ``setAddresses()`` and/or ``setNameAddresses()``:: $to = $message->getHeaders()->get('To'); $to->setAddresses('joe-bloggs@example.org'); When output via ``toString()``, a mailbox header produces something like the following:: $to = $message->getHeaders()->get('To'); $to->setNameAddresses([ 'person1@example.org' => 'Name of Person', 'person2@example.org', 'person3@example.org' => 'Another Person' ]); echo $to->toString(); /* To: Name of Person <person1@example.org>, person2@example.org, Another Person <person3@example.org> */ Internationalized domains are automatically converted to IDN encoding:: $to = $message->getHeaders()->get('To'); $to->setAddresses('joe@ëxämple.org'); echo $to->toString(); /* To: joe@xn--xmple-gra1c.org */ ID Headers ~~~~~~~~~~ ID headers contain identifiers for the entity (or the message). The most notable ID header is the Message-ID header on the message itself. An ID that exists inside an ID header looks more-or-less less like an email address. For example, ``<1234955437.499becad62ec2@example.org>``. The part to the left of the @ sign is usually unique, based on the current time and some random factor. The part on the right is usually a domain name. Any ID passed to the header's ``setId()`` method absolutely MUST conform to this structure, otherwise you'll get an Exception thrown at you by Swift Mailer (a ``Swift_RfcComplianceException``). This is to ensure that the generated email complies with relevant RFC documents and therefore is less likely to be blocked as spam. It's easy to add a new ID header to a HeaderSet. You do this by calling the HeaderSet's ``addIdHeader()`` method:: $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addIdHeader('Your-Header-Name', '123456.unqiue@example.org'); Changing the value of an existing ID header is done by calling its ``setId()`` method:: $msgId = $message->getHeaders()->get('Message-ID'); $msgId->setId(time() . '.' . uniqid('thing') . '@example.org'); When output via ``toString()``, an ID header produces something like the following:: $msgId = $message->getHeaders()->get('Message-ID'); echo $msgId->toString(); /* Message-ID: <1234955437.499becad62ec2@example.org> */ Path Headers ~~~~~~~~~~~~ Path headers are like very-restricted mailbox headers. They contain a single email address with no associated name. The Return-Path header of a message is a path header. You add a new path header to a HeaderSet by calling the HeaderSet's ``addPathHeader()`` method:: $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addPathHeader('Your-Header-Name', 'person@example.org'); Changing the value of an existing path header is done by calling its ``setAddress()`` method:: $return = $message->getHeaders()->get('Return-Path'); $return->setAddress('my-address@example.org'); When output via ``toString()``, a path header produces something like the following:: $return = $message->getHeaders()->get('Return-Path'); $return->setAddress('person@example.org'); echo $return->toString(); /* Return-Path: <person@example.org> */ Header Operations ----------------- Working with the headers in a message involves knowing how to use the methods on the HeaderSet and on the individual Headers within the HeaderSet. Adding new Headers ~~~~~~~~~~~~~~~~~~ New headers can be added to the HeaderSet by using one of the provided ``add..Header()`` methods. The added header will appear in the message when it is sent:: // Adding a custom header to a message $message = new Swift_Message(); $headers = $message->getHeaders(); $headers->addTextHeader('X-Mine', 'something here'); // Adding a custom header to an attachment $attachment = Swift_Attachment::fromPath('/path/to/doc.pdf'); $attachment->getHeaders()->addDateHeader('X-Created-Time', time()); Retrieving Headers ~~~~~~~~~~~~~~~~~~ Headers are retrieved through the HeaderSet's ``get()`` and ``getAll()`` methods:: $headers = $message->getHeaders(); // Get the To: header $toHeader = $headers->get('To'); // Get all headers named "X-Foo" $fooHeaders = $headers->getAll('X-Foo'); // Get the second header named "X-Foo" $foo = $headers->get('X-Foo', 1); // Get all headers that are present $all = $headers->getAll(); When using ``get()`` a single header is returned that matches the name (case insensitive) that is passed to it. When using ``getAll()`` with a header name, an array of headers with that name are returned. Calling ``getAll()`` with no arguments returns an array of all headers present in the entity. .. note:: It's valid for some headers to appear more than once in a message (e.g. the Received header). For this reason ``getAll()`` exists to fetch all headers with a specified name. In addition, ``get()`` accepts an optional numerical index, starting from zero to specify which header you want more specifically. .. note:: If you want to modify the contents of the header and you don't know for sure what type of header it is then you may need to check the type by calling its ``getFieldType()`` method. Check if a Header Exists ~~~~~~~~~~~~~~~~~~~~~~~~ You can check if a named header is present in a HeaderSet by calling its ``has()`` method:: $headers = $message->getHeaders(); // Check if the To: header exists if ($headers->has('To')) { echo 'To: exists'; } // Check if an X-Foo header exists twice (i.e. check for the 2nd one) if ($headers->has('X-Foo', 1)) { echo 'Second X-Foo header exists'; } If the header exists, ``true`` will be returned or ``false`` if not. .. note:: It's valid for some headers to appear more than once in a message (e.g. the Received header). For this reason ``has()`` accepts an optional numerical index, starting from zero to specify which header you want to check more specifically. Removing Headers ~~~~~~~~~~~~~~~~ Removing a Header from the HeaderSet is done by calling the HeaderSet's ``remove()`` or ``removeAll()`` methods:: $headers = $message->getHeaders(); // Remove the Subject: header $headers->remove('Subject'); // Remove all X-Foo headers $headers->removeAll('X-Foo'); // Remove only the second X-Foo header $headers->remove('X-Foo', 1); When calling ``remove()`` a single header will be removed. When calling ``removeAll()`` all headers with the given name will be removed. If no headers exist with the given name, no errors will occur. .. note:: It's valid for some headers to appear more than once in a message (e.g. the Received header). For this reason ``remove()`` accepts an optional numerical index, starting from zero to specify which header you want to check more specifically. For the same reason, ``removeAll()`` exists to remove all headers that have the given name. Modifying a Header's Content ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To change a Header's content you should know what type of header it is and then call it's appropriate setter method. All headers also have a ``setFieldBodyModel()`` method that accepts a mixed parameter and delegates to the correct setter:: The header will be updated inside the HeaderSet and the changes will be seen when the message is sent:: $headers = $message->getHeaders(); // Change the Subject: header $subj = $headers->get('Subject'); $subj->setValue('new subject here'); // Change the To: header $to = $headers->get('To'); $to->setNameAddresses([ 'person@example.org' => 'Person', 'thing@example.org' ]); // Using the setFieldBodyModel() just delegates to the correct method // So here to calls setNameAddresses() $to->setFieldBodyModel([ 'person@example.org' => 'Person', 'thing@example.org' ]); swiftmailer/doc/index.rst 0000777 00000000207 14710744267 0011522 0 ustar 00 Swiftmailer =========== .. toctree:: :maxdepth: 2 introduction messages headers sending plugins japanese swiftmailer/doc/japanese.rst 0000777 00000001050 14710744267 0012176 0 ustar 00 Using Swift Mailer for Japanese Emails ====================================== To send emails in Japanese, you need to tweak the default configuration. Call the ``Swift::init()`` method with the following code as early as possible in your code:: Swift::init(function () { Swift_DependencyContainer::getInstance() ->register('mime.qpheaderencoder') ->asAliasOf('mime.base64headerencoder'); Swift_Preferences::getInstance()->setCharset('iso-2022-jp'); }); /* rest of code goes here */ That's all! swiftmailer/.gitattributes 0000777 00000000333 14710744267 0012007 0 ustar 00 *.crt -crlf *.key -crlf *.srl -crlf *.pub -crlf *.priv -crlf *.txt -crlf # ignore directories in the git-generated distributed .zip archive /doc/notes export-ignore /tests export-ignore /phpunit.xml.dist export-ignore swiftmailer/README.md 0000777 00000002065 14710744267 0010377 0 ustar 00 Swift Mailer ------------ **Swiftmailer will stop being maintained at the end of November 2021.** Please, move to [Symfony Mailer](https://symfony.com/doc/current/mailer.html) at your earliest convenience. [Symfony Mailer](https://symfony.com/doc/current/mailer.html) is the next evolution of Swiftmailer. It provides the same features with support for modern PHP code and support for third-party providers. Swift Mailer is a component based mailing solution for PHP. It is released under the MIT license. Swift Mailer is highly object-oriented by design and lends itself to use in complex web application with a great deal of flexibility. For full details on usage, read the [documentation](https://swiftmailer.symfony.com/docs/introduction.html). Sponsors -------- <div> <a href="https://blackfire.io/docs/introduction?utm_source=swiftmailer&utm_medium=github_readme&utm_campaign=logo"> <img src="https://static.blackfire.io/assets/intemporals/logo/png/blackfire-io_secondary_horizontal_transparent.png?1" width="255px" alt="Blackfire.io"> </a> </div> swiftmailer/.github/workflows/tests.yml 0000777 00000002636 14710744267 0014406 0 ustar 00 name: tests on: push: pull_request: jobs: linux_tests: runs-on: ubuntu-20.04 services: mailcatcher: image: dockage/mailcatcher:0.7.1 ports: - 4456:1025 strategy: fail-fast: true matrix: php: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] name: PHP ${{ matrix.php }} steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, intl tools: composer:v2 coverage: none - name: Prepare test config files run: | cp tests/acceptance.conf.php.default tests/acceptance.conf.php cp tests/smoke.conf.php.default tests/smoke.conf.php - name: Require Symfony PHPUnit Bridge 5.4 for PHP 8.1 if: ${{ matrix.php >= 8.1 }} run: composer require symfony/phpunit-bridge:^5.4 --dev --prefer-dist --no-interaction --no-progress - name: Install dependencies uses: nick-invision/retry@v1 with: timeout_minutes: 5 max_attempts: 5 command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress - name: Execute tests run: vendor/bin/simple-phpunit --verbose env: SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: 1 swiftmailer/.github/ISSUE_TEMPLATE.md 0000777 00000000753 14710744267 0013167 0 ustar 00 <!-- Please fill in this template according to your issue. --> | Q | A | ------------------- | ----- | Bug report? | yes/no | Feature request? | yes/no | RFC? | yes/no | How used? | Standalone/Symfony/3party | Swiftmailer version | x.y.z | PHP version | x.y.z ### Observed behaviour <!-- What does the code do? --> ### Expected behaviour <!-- What should the code do? --> ### Example <!-- Example to reproduce the issue. --> swiftmailer/.github/PULL_REQUEST_TEMPLATE.md 0000777 00000000625 14710744267 0014261 0 ustar 00 <!-- Please fill in this template according to the PR you're about to submit. --> | Q | A | ------------- | --- | Bug fix? | yes/no | New feature? | yes/no | Doc update? | yes/no | BC breaks? | yes/no | Deprecations? | yes/no | Fixed tickets | #... <!-- #-prefixed issue number(s), if any --> | License | MIT <!-- Replace this comment by the description of your issue. --> swiftmailer/LICENSE 0000777 00000002051 14710744267 0010120 0 ustar 00 Copyright (c) 2013-2021 Fabien Potencier 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. swiftmailer/.gitignore 0000777 00000000217 14710744267 0011105 0 ustar 00 /.php_cs.cache /.phpunit /.phpunit.result.cache /build/* /composer.lock /phpunit.xml /tests/acceptance.conf.php /tests/smoke.conf.php /vendor/ swiftmailer/CHANGES 0000777 00000027755 14710744267 0010130 0 ustar 00 Changelog ========= **Swiftmailer will stop being maintained at the end of November 2021.** Please, move to Symfony Mailer at your earliest convenience. Symfony Mailer is the next evolution of Swiftmailer. It provides the same features with support for modern PHP code and support for third-party providers. See https://symfony.com/doc/current/mailer.html for more information. 6.3.0 (2021-10-18) ------------------ * Fix support for PHP 8.1 6.2.7 (2021-03-09) ------------------ * Allow egulias/email-validator 3.1+ 6.2.6 (2021-03-05) ------------------ * Fix Bcc support 6.2.5 (2021-01-12) ------------------ * Don't trust properties at destruct time * Remove invalid PHPDocs param in EventDispatcher interface * Bump license year * Removes PHP version from README 6.2.4 (2020-12-08) ------------------ * Prevent flushing of the bubble queue when event handler raises another event * Add support for PHP 8 * Code cleanups 6.2.3 (2019-11-12) ------------------ * no changes 6.2.2 (2019-11-12) ------------------ * fixed compat with PHP 7.4 * fixed error message when connecting to a stream raises an error before connect() 6.2.1 (2019-04-21) ------------------ * reverted "deprecated Swift_CharacterStream_ArrayCharacterStream and Swift_CharacterStream_NgCharacterStream in favor of Swift_CharacterStream_CharacterStream" 6.2.0 (2019-03-10) ------------------ * added support for symfony/polyfill-intl-dn * deprecated Swift_CharacterStream_ArrayCharacterStream and Swift_CharacterStream_NgCharacterStream in favor of Swift_CharacterStream_CharacterStream 6.1.3 (2018-09-11) ------------------ * added auto-start to the SMTP transport when sending a message * tweaked error message when the response from an SMTP server is empty * fixed missing property in Swift_Mime_IdGenerator * exposed original body content type with Swift_Mime_SimpleMimeEntity::getBodyContentType() * fixed typo in variable name in Swift_AddressEncoder_IdnAddressEncoder * fixed return type in MessageLogger * fixed missing property addressEncoder in SimpleHeaderFactory class 6.1.2 (2018-07-13) ------------------ * handled recipient errors when pipelining 6.1.1 (2018-07-04) ------------------ * removed hard dependency on an IDN encoder 6.1.0 (2018-07-02) ------------------ * added address encoder exceptions during send * added support for bubbling up authenticator error messages * added support for non-ASCII email addresses * introduced new dependencies: transport.smtphandlers and transport.authhandlers * deprecated Swift_Signers_OpenDKIMSigner; use Swift_Signers_DKIMSigner instead * added support for SMTP pipelining * added Swift_Transport_Esmtp_EightBitMimeHandler * fixed startTLS only allowed tls1.0, now allowed: tls1.0, tls1.1, tls1.2 6.0.2 (2017-09-30) ------------------ * fixed DecoratorPlugin * removed usage of getmypid() 6.0.1 (2017-05-20) ------------------ * fixed BC break that can be avoided easily 6.0.0 (2017-05-19) ------------------ * added Swift_Transport::ping() * removed Swift_Mime_HeaderFactory, Swift_Mime_HeaderSet, Swift_Mime_Message, Swift_Mime_MimeEntity, and Swift_Mime_ParameterizedHeader interfaces * removed Swift_MailTransport and Swift_Transport_MailTransport * removed Swift_Encoding * removed the Swift_Transport_MailInvoker interface and Swift_Transport_SimpleMailInvoker class * removed the Swift_SignedMessage class * removed newInstance() methods everywhere * methods operating on Date header now use DateTimeImmutable object instead of Unix timestamp; Swift_Mime_Headers_DateHeader::getTimestamp()/setTimestamp() renamed to getDateTime()/setDateTime() * bumped minimum version to PHP 7.0 * removed Swift_Validate and replaced by egulias/email-validator 5.4.9 (2018-01-23) ------------------ * no changes, last version of the 5.x series 5.4.8 (2017-05-01) ------------------ * fixed encoding inheritance in addPart() * fixed sorting MIME children when their types are equal 5.4.7 (2017-04-20) ------------------ * fixed NTLMAuthenticator clobbering bcmath scale 5.4.6 (2017-02-13) ------------------ * removed exceptions thrown in destructors as they lead to fatal errors * switched to use sha256 by default in DKIM as per the RFC * fixed an 'Undefined variable: pipes' PHP notice * fixed long To headers when using the mail transport * fixed NTLMAuthenticator when no domain is passed with the username * prevented fatal error during unserialization of a message * fixed a PHP warning when sending a message that has a length of a multiple of 8192 5.4.5 (2016-12-29) ------------------ * SECURITY FIX: fixed CVE-2016-10074 by disallowing potentially unsafe shell characters Prior to 5.4.5, the mail transport (Swift_Transport_MailTransport) was vulnerable to passing arbitrary shell arguments if the "From", "ReturnPath" or "Sender" header came from a non-trusted source, potentially allowing Remote Code Execution * deprecated the mail transport 5.4.4 (2016-11-23) ------------------ * reverted escaping command-line args to mail (PHP mail() function already does it) 5.4.3 (2016-07-08) ------------------ * fixed SimpleHeaderSet::has()/get() when the 0 index is removed * removed the need to have mcrypt installed * fixed broken MIME header encoding with quotes/colons and non-ascii chars * allowed mail transport send for messages without To header * fixed PHP 7 support 5.4.2 (2016-05-01) ------------------ * fixed support for IPv6 sockets * added auto-retry when sending messages from the memory spool * fixed consecutive read calls in Swift_ByteStream_FileByteStream * added support for iso-8859-15 encoding * fixed PHP mail extra params on missing reversePath * added methods to set custom stream context options * fixed charset changes in QpContentEncoderProxy * added return-path header to the ignoredHeaders list of DKIMSigner * fixed crlf for subject using mail * fixed add soft line break only when necessary * fixed escaping command-line args to mail 5.4.1 (2015-06-06) ------------------ * made Swiftmailer exceptions confirm to PHP base exception constructor signature * fixed MAIL FROM & RCPT TO headers to be RFC compliant 5.4.0 (2015-03-14) ------------------ * added the possibility to add extra certs to PKCS#7 signature * fix base64 encoding with streams * added a new RESULT_SPOOLED status for SpoolTransport * fixed getBody() on attachments when called more than once * removed dots from generated filenames in filespool 5.3.1 (2014-12-05) ------------------ * fixed cloning of messages with attachments 5.3.0 (2014-10-04) ------------------ * fixed cloning when using signers * reverted removal of Swift_Encoding * drop support for PHP 5.2.x 5.2.2 (2014-09-20) ------------------ * fixed Japanese support * fixed the memory spool when the message changes when in the pool * added support for cloning messages * fixed PHP warning in the redirect plugin * changed the way to and cc-ed email are sent to only use one transaction 5.2.1 (2014-06-13) ------------------ * SECURITY FIX: fixed CLI escaping when using sendmail as a transport Prior to 5.2.1, the sendmail transport (Swift_Transport_SendmailTransport) was vulnerable to an arbitrary shell execution if the "From" header came from a non-trusted source and no "Return-Path" is configured. * fixed parameter in DKIMSigner * fixed compatibility with PHP < 5.4 5.2.0 (2014-05-08) ------------------ * fixed Swift_ByteStream_FileByteStream::read() to match to the specification * fixed from-charset and to-charset arguments in mbstring_convert_encoding() usages * fixed infinite loop in StreamBuffer * fixed NullTransport to return the number of ignored emails instead of 0 * Use phpunit and mockery for unit testing (realityking) 5.1.0 (2014-03-18) ------------------ * fixed data writing to stream when sending large messages * added support for libopendkim (https://github.com/xdecock/php-opendkim) * merged SignedMessage and Message * added Gmail XOAuth2 authentication * updated the list of known mime types * added NTLM authentication 5.0.3 (2013-12-03) ------------------ * fixed double-dot bug * fixed DKIM signer 5.0.2 (2013-08-30) ------------------ * handled correct exception type while reading IoBuffer output 5.0.1 (2013-06-17) ------------------ * changed the spool to only start the transport when a mail has to be sent * fixed compatibility with PHP 5.2 * fixed LICENSE file 5.0.0 (2013-04-30) ------------------ * changed the license from LGPL to MIT 4.3.1 (2013-04-11) ------------------ * removed usage of the native QP encoder when the charset is not UTF-8 * fixed usage of uniqid to avoid collisions * made a performance improvement when tokenizing large headers * fixed usage of the PHP native QP encoder on PHP 5.4.7+ 4.3.0 (2013-01-08) ------------------ * made the temporary directory configurable via the TMPDIR env variable * added S/MIME signer and encryption support 4.2.2 (2012-10-25) ------------------ * added the possibility to throttle messages per second in ThrottlerPlugin (mostly for Amazon SES) * switched mime.qpcontentencoder to automatically use the PHP native encoder on PHP 5.4.7+ * allowed specifying a whitelist with regular expressions in RedirectingPlugin 4.2.1 (2012-07-13) ------------------ * changed the coding standards to PSR-1/2 * fixed issue with autoloading * added NativeQpContentEncoder to enhance performance (for PHP 5.3+) 4.2.0 (2012-06-29) ------------------ * added documentation about how to use the Japanese support introduced in 4.1.8 * added a way to override the default configuration in a lazy way * changed the PEAR init script to lazy-load the initialization * fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8) 4.1.8 (2012-06-17) ------------------ * added Japanese iso-2022-jp support * changed the init script to lazy-load the initialization * fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks * fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids * fixed encoding of email addresses in headers * added replacements setter to the Decorator plugin 4.1.7 (2012-04-26) ------------------ * fixed QpEncoder safeMapShareId property 4.1.6 (2012-03-23) ------------------ * reduced the size of serialized Messages 4.1.5 (2012-01-04) ------------------ * enforced Swift_Spool::queueMessage() to return a Boolean * made an optimization to the memory spool: start the transport only when required * prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead * fixed a PHP warning when calling to mail() when safe_mode is off * many doc tweaks 4.1.4 (2011-12-16) ------------------ * added a memory spool (Swift_MemorySpool) * fixed too many opened files when sending emails with attachments 4.1.3 (2011-10-27) ------------------ * added STARTTLS support * added missing @return tags on fluent methods * added a MessageLogger plugin that logs all sent messages * added composer.json 4.1.2 (2011-09-13) ------------------ * fixed wrong detection of magic_quotes_runtime * fixed fatal errors when no To or Subject header has been set * fixed charset on parameter header continuations * added documentation about how to install Swiftmailer from the PEAR channel * fixed various typos and markup problem in the documentation * fixed warning when cache directory does not exist * fixed "slashes are escaped" bug * changed require_once() to require() in autoload 4.1.1 (2011-07-04) ------------------ * added missing file in PEAR package 4.1.0 (2011-06-30) ------------------ * documentation has been converted to ReST 4.1.0 RC1 (2011-06-17) ---------------------- New features: * changed the Decorator Plugin to allow replacements in all headers * added Swift_Mime_Grammar and Swift_Validate to validate an email address * modified the autoloader to lazy-initialize Swiftmailer * removed Swift_Mailer::batchSend() * added NullTransport * added new plugins: RedirectingPlugin and ImpersonatePlugin * added a way to send messages asynchronously (Spool) swiftmailer/.php_cs.dist 0000777 00000001477 14710744267 0011345 0 ustar 00 <?php return PhpCsFixer\Config::create() ->setRules([ '@Symfony' => true, '@Symfony:risky' => true, '@PHPUnit75Migration:risky' => true, 'php_unit_dedicate_assert' => ['target' => '5.6'], 'array_syntax' => ['syntax' => 'short'], 'php_unit_fqcn_annotation' => true, 'no_unreachable_default_argument_value' => false, 'braces' => ['allow_single_line_closure' => true], 'heredoc_to_nowdoc' => false, 'ordered_imports' => true, 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], 'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'all'], 'fopen_flags' => false, ]) ->setRiskyAllowed(true) ->setFinder(PhpCsFixer\Finder::create()->in(__DIR__)) ;
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Генерация страницы: 0.04 |
proxy
|
phpinfo
|
Настройка