├── README.md ├── docs ├── email_builder.md ├── mime_parser.md ├── pop3.md └── smtp.md ├── support ├── Net │ ├── DNS2.php │ └── license.txt ├── cacert.pem ├── email_builder.php ├── ipaddr.php ├── mime_parser.php ├── pop3.php ├── smtp.php ├── tag_filter.php ├── utf8.php └── utf_utils.php └── test_suite ├── run.php ├── test_1.txt ├── test_2.txt ├── test_3.txt ├── test_4.txt ├── test_5.txt ├── test_6.txt └── test_newsletter_header.png /README.md: -------------------------------------------------------------------------------- 1 | Ultimate E-mail Toolkit 2 | ======================= 3 | 4 | A PHP library of functions designed to handle all of your one-off e-mail needs under a MIT or LGPL license. Instead of relying solely on the mostly broken PHP mail() function, this library directly talks to SMTP and POP3 servers just as a regular e-mail client would. The result is a high level of reliability in delivery of e-mail messages to recipients. Functions like `ConvertHTMLToText()` and `MakeValidEmailAddress()` make it easy to do complex tasks such as convert ugly HTML input into beautiful plain-text output and analyze an e-mail address to automatically correct common typing mistakes. All of that while following the various RFCs surrounding e-mail. 5 | 6 | [](https://cubiclesoft.com/donate/) [](https://cubiclesoft.com/product-support/github/) 7 | 8 | Features 9 | -------- 10 | 11 | * Carefully follows the many IETF RFC Standards surrounding e-mail (RFC822, RFC2822, RFC1341, RFC1342, RFC1081, RFC1939, RFC2045, etc). 12 | * Relatively complete and comprehensive, yet easy-to-use SMTP, POP3, and MIME libraries. Fully MIME and Unicode-aware. 13 | * Easy to emulate various e-mail client headers. 14 | * Rapidly build [great-looking, fully responsive HTML e-mails](https://github.com/cubiclesoft/ultimate-email/blob/master/docs/email_builder.md) with the included `EmailBuilder` class. 15 | * `SMTP::ConvertHTMLToText()` to convert ugly HTML into really nice-looking plain text suitable for multipart e-mails. 16 | * `SMTP::MakeValidEmailAddress()` to correctly parse e-mail addresses and automatically correct common typing mistakes. 17 | * Has a liberal open source license. MIT or LGPL, your choice. 18 | * Designed for relatively painless integration into your project. 19 | * Sits on GitHub for all of that pull request and issue tracker goodness to easily submit changes and ideas respectively. 20 | 21 | Usage 22 | ----- 23 | 24 | Documentation and examples can be found in the 'docs' directory of this repository. 25 | 26 | * [EmailBuilder class](https://github.com/cubiclesoft/ultimate-email/blob/master/docs/email_builder.md) - Effortlessly design beautiful HTML e-mails. 27 | * [SMTP class](https://github.com/cubiclesoft/ultimate-email/blob/master/docs/smtp.md) - Send e-mail. 28 | * [POP3 class](https://github.com/cubiclesoft/ultimate-email/blob/master/docs/pop3.md) - Retrieve e-mail. 29 | * [MIMEParser class](https://github.com/cubiclesoft/ultimate-email/blob/master/docs/mime_parser.md) - Extract content from retrieved e-mail. 30 | -------------------------------------------------------------------------------- /docs/email_builder.md: -------------------------------------------------------------------------------- 1 | EmailBuilder Class: 'support/email_builder.php' 2 | ================================================ 3 | 4 | EmailBuilder is a powerful generator/builder class that creates beautiful, fully responsive, table-based HTML emails to be used later with the SMTP class. Uses a natural PHP arrays approach. 5 | 6 | Example: 7 | 8 | ```php 9 | require_once "support/email_builder.php"; 10 | 11 | // Write normal CSS. 12 | $styles = array( 13 | "a" => "text-decoration: none;", 14 | "#headerwrap" => "font-size: 0; line-height: 0;", 15 | "#contentwrap" => "font-family: Helvetica, Arial, sans-serif; font-size: 18px; line-height: 27px; color: #333333;", 16 | "#contentwrap a:not(.bigbutton)" => "color: #4E88C2;", 17 | "#contentwrap a.bigbutton" => "font-family: Helvetica, Arial, sans-serif; font-size: 18px; line-height: 27px; color: #FEFEFE;", 18 | "#footerwrap" => "font-family: Helvetica, Arial, sans-serif; font-size: 14px; line-height: 21px; color: #F0F0F0;", 19 | "#footerwrap a" => "color: #CCCCCC;" 20 | ); 21 | 22 | $content = array( 23 | // Header. 24 | array( 25 | "type" => "layout", 26 | "id" => "headerwrap", 27 | // "table-bgcolor" => "#FF0000", 28 | "width" => 600, 29 | "content" => array( 30 | array( 31 | "type" => "image", 32 | "width" => 600, 33 | // "src" => "http://localhost/ultimate-email/test_suite/test_newsletter_header.png", 34 | "file" => "test_suite/test_newsletter_header.png" 35 | ) 36 | ) 37 | ), 38 | 39 | // Main content. 40 | array( 41 | "type" => "layout", 42 | "width" => 600, 43 | "content" => array( 44 | array( 45 | "type" => "layout", 46 | "id" => "contentwrap", 47 | "width" => "90%", 48 | "content" => array( 49 | array("type" => "space", "height" => 1), 50 | 51 | "
Hello valued humanoid!
", 52 | 53 | // Float an image to the right. 54 | array( 55 | "type" => "layout", 56 | // "table-width" => "35%", 57 | "table-align" => "right", 58 | "width" => 100, 59 | "padding" => array(5, 0, 20, 20), 60 | "content" => array( 61 | array( 62 | "type" => "image", 63 | "width" => 100, 64 | "src" => "http://lorempixel.com/g/100/150/technics/1/", 65 | "alt" => "Circuitry" 66 | ) 67 | ) 68 | ), 69 | 70 | "Blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
", 71 | "Blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
", 72 | "", 73 | "Blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
", 74 | 75 | // Display a clickable link as a centered button (e.g. a call to action). 76 | array( 77 | "type" => "layout", 78 | "align" => "center", 79 | "content" => array( 80 | array( 81 | "type" => "button", 82 | "href" => "#", 83 | // "target" => "_blank", 84 | "class" => "bigbutton", 85 | "bgcolor" => "#4E88C2", 86 | "padding" => array(12, 18), 87 | "text" => "Take the survey" 88 | ) 89 | ) 90 | ), 91 | 92 | // Spacers and a splitter. 93 | array("type" => "space", "height" => 20), 94 | array("type" => "split", "bgcolor" => "#F0F0F0"), 95 | array("type" => "space", "height" => 5), 96 | 97 | "Sincerely,
", 98 | "Blah blah blah
", 99 | 100 | array("type" => "space", "height" => 1), 101 | ) 102 | ) 103 | ) 104 | ), 105 | 106 | // Footer. 107 | array( 108 | "type" => "layout", 109 | "width" => 600, 110 | "bgcolor" => "#182434", 111 | "content" => array( 112 | array( 113 | "type" => "layout", 114 | "id" => "footerwrap", 115 | "width" => "90%", 116 | "content" => array( 117 | array("type" => "space", "height" => 1), 118 | 119 | "Blah blah blah
", 120 | "", 121 | "Blah blah blah
", 122 | 123 | array("type" => "space", "height" => 1), 124 | ) 125 | ) 126 | ) 127 | ) 128 | ); 129 | 130 | $result = EmailBuilder::Generate($styles, $content); 131 | 132 | echo $result["html"]; 133 | ?> 134 | ``` 135 | 136 | Output: 137 | 138 |  139 | 140 | EmailBuilder::RegisterHandler($mode, $callback) 141 | ----------------------------------------------- 142 | 143 | Access: public static 144 | 145 | Parameters: 146 | 147 | * $mode - A string containing one of "init", "custom_type", or "finalize". 148 | * $callback - A valid callback function for the specified mode. The callback function must accept the correct number and type of inputs. 149 | 150 | Returns: Nothing. 151 | 152 | This static function is the basis of adding new functionality to the EmailBuilder class. Callbacks are executed in a specific sequence for managing field modifications in an efficient manner. 153 | 154 | EmailBuilder::InitContentOpts(&$contentopts) 155 | -------------------------------------------- 156 | 157 | Access: protected static 158 | 159 | Parameters: 160 | 161 | * $contentopts - An array containing options used to generate the HTML. 162 | 163 | Returns: Nothing. 164 | 165 | This internal static function initializes any registered "init" handlers. The $contentopts array may be modified. 166 | 167 | EmailBuilder::AlterOption(&$html, &$inlineimages, &$option, $prefix) 168 | -------------------------------------------------------------------- 169 | 170 | Access: protected static 171 | 172 | Parameters: 173 | 174 | * $html - A string containing the HTML generated so far. 175 | * $inlineimages - An array containing inline images added so far. 176 | * $option - An array containing the current option being processed. 177 | * $prefix - A string containing the current output prefix. 178 | 179 | Returns: Nothing. 180 | 181 | This internal static function allows any registered "custom_type" handlers to process the current option. 182 | 183 | EmailBuilder::Finalize(&$html, &$contentopts) 184 | --------------------------------------------- 185 | 186 | Access: protected static 187 | 188 | Parameters: 189 | 190 | * $html - A string containing the HTML generated so far. 191 | * $contentopts - An array containing options used to generate the HTML. 192 | 193 | Returns: Nothing. 194 | 195 | This internal static function runs any registered "finalize" handlers. 196 | 197 | EmailBuilder::ProcessContentOpts(&$html, &$inlineimages, &$contentopts, $prefix) 198 | -------------------------------------------------------------------------------- 199 | 200 | Access: _internal_ static 201 | 202 | Parameters: 203 | 204 | * $html - A string containing the HTML generated so far. 205 | * $inlineimages - An array containing inline images added so far. 206 | * $contentopts - An array containing the current level of options being processed. 207 | * $prefix - A string containing the current output prefix. 208 | 209 | Returns: Nothing. 210 | 211 | This mostly internal static function processes the current level of options to generate the correct HTML output. Options may be processed recursively. 212 | 213 | EmailBuilder::Generate($styles, $contentopts) 214 | --------------------------------------------- 215 | 216 | Access: public static 217 | 218 | Parameters: 219 | 220 | * $styles - An array of key-value pairs that maps CSS3 selectors to strings containing styles to apply to the targets. 221 | * $contentopts - An array of options that describe how to generate the HTML content. 222 | 223 | Returns: A standard array of information. 224 | 225 | This static function takes in two arrays of information containing CSS3 styles to apply inline and a set of options that defines how the HTML will be generated for the email. First, `EmailBuilder::ProcessContentOpts()` is called and the HTML is generated. Then inline styles are applied to the generated HTML using the $styles array, 'id' and 'class' attributes are removed, and the result is returned. 226 | 227 | The $contentopts array is very flexible and options vary depending on the option. An option can be a string or an array. When the option is a string, it is assumed to be valid HTML and included as-is (NOTE: TagFilter may correct invalid HTML later in the process). 228 | 229 | When the option is an array of key-value pairs, the "type" may be one of: 230 | 231 | * layout - A highly flexible horizontal layout with positioning, including float emulation support. 232 | * space - A vertical spacer. 233 | * split - A horizontal line/splitter. 234 | * button - A clickable link displayed as a button (e.g. call to action). 235 | * image - A responsive/scaled image with optional inline embedding support (i.e. `cid:`). 236 | 237 | Type-specific options: 238 | 239 | * padding (layout, button) - An integer or array of integers containing standard CSS padding declarations for top, right, bottom, left. 240 | * table-width (layout) - A string or integer containing the width of the table (Default is "100%"). Should be a percentage or in pixels. 241 | * table-bgcolor (layout) - A string containing the background color for the table. Should be in the format "#RRGGBB" for maximum compatibility. 242 | * table-class (layout) - A string containing one or more CSS classes to apply to the table element. 243 | * table-align (layout) - A string containing one of "left", "right", "center" to apply to the table element. Useful for simulating floats. 244 | * width (layout) - A string or integer containing the width of the main content area for the layout. When both 'width' and 'padding' are defined, 'table-width' is forced to be a precise pixel count. 245 | * align (layout) - A string containing one of "left", "right", "center" to align the content inside. 246 | * row-align (layout) - A string containing one of "left", "right", "center" to align the content region when 'width' is defined and 'padding' is not defined (Default is "center"). This creates a responsive content layout. 247 | * bgcolor (layout, space, split, button) - A string containing the background color to use. For layouts, this is the background color of the content area. Should be in the format "#RRGGBB" for maximum compatibility. 248 | * style (layout, button, image) - A string containing CSS styles to append to the style attribute. For layouts, this is applied to the content area. 249 | * id (layout, button, image) - A string containing a CSS ID to apply. For layouts, this is applied to the content area. 250 | * class (layout, button, image) - A string containing one or more CSS classes to apply. For layouts, this is applied to the content area. 251 | * content (layout) - An array containing more $contentopts options. `EmailBuilder::ProcessContentOpts()` is called recursively to process the options. 252 | * height (space, split) - An integer containing the number of vertical pixels for the spacer/splitter. 253 | * border-radius (button) - An integer containing the number of pixels to use for the corners of the button (Default is 4). 254 | * href (button) - A string containing the URL to link to. 255 | * target (button) - A string containing the window target (e.g. "_blank"). 256 | * text (button) - A string containing the text to use. Will be escaped. 257 | * html (button) - A string containing the HTML to use. 258 | * file (image) - A string containing the filename of the file to embed/inline as a "cid:" (Content-ID) image. The file must be JPEG, PNG, or GIF. May appear as a file attachment in some email clients in addition to being embedded. 259 | * src (image) - A string containing the URL of the image to load. Note that email clients won't automatically load this type of image. 260 | * alt (image) - A string containing alt text for the image. 261 | * width (image) - An integer containing the width, in pixels, to display the image. 262 | * height (image) - An integer containing the height, in pixels, to display the image. 263 | -------------------------------------------------------------------------------- /docs/mime_parser.md: -------------------------------------------------------------------------------- 1 | MIMEParser Class: 'support/mime_parser.php' 2 | =========================================== 3 | 4 | The MIMEParser class extracts content from e-mails retrieved with the POP3 class allowing for deep message analysis and processing. If you are extracting HTML with this, the [TagFilter class](https://github.com/cubiclesoft/ultimate-web-scraper) will prove useful for extracting content from the HTML. 5 | 6 | Example usage: 7 | 8 | ```php 9 | "[pop3.yourhost.com]", 17 | "port" => [110 or 995], 18 | "secure" => [true or false] 19 | ); 20 | 21 | $pop3 = new POP3(); 22 | $result = $pop3->Connect("[YOUR e-mail username]", "[YOUR e-mail password]", $pop3options); 23 | if (!$result["success"]) 24 | { 25 | echo "POP3 - Connect(): " . $result["error"] . "\n"; 26 | 27 | exit(); 28 | } 29 | 30 | $result = $pop3->GetMessageList(); 31 | if (!$result["success"]) 32 | { 33 | echo "POP3 - GetMessageList(): " . $result["error"] . "\n"; 34 | 35 | exit(); 36 | } 37 | 38 | $ids = $result["ids"]; 39 | foreach ($ids as $id => $size) 40 | { 41 | // Only retrieve messages under 1MB. 42 | if ($size < 1024768) 43 | { 44 | $result = $pop3->GetNextMessage($id); 45 | if (!$result["success"]) 46 | { 47 | echo "POP3 - GetNextMessage(): " . $result["error"] . "\n"; 48 | 49 | exit(); 50 | } 51 | 52 | $message = $result["message"]; 53 | 54 | // Process the message. 55 | $message = MIMEParser::Parse($result["message"]); 56 | var_dump($message); 57 | 58 | $content = MIMEParser::ExtractContent($message); 59 | var_dump($content); 60 | } 61 | 62 | // $result = $pop3->DeleteMessage($id); 63 | // if (!$result["success"]) 64 | // { 65 | // echo "POP3 - DeleteMessage(): " . $result["error"] . "\n"; 66 | // 67 | // exit(); 68 | // } 69 | } 70 | 71 | $pop3->Disconnect(); 72 | ?> 73 | ``` 74 | 75 | MIMEParser::ConvertFromRFC1341($data) 76 | ------------------------------------- 77 | 78 | Access: public static 79 | 80 | Parameters: 81 | 82 | * $data - A string containing the data to convert. 83 | 84 | Returns: A string containing the converted data. 85 | 86 | This static function converts RFC 1341 encoded data (also known as "Quoted Printable") into 8-bit clean data. 8-bit data (e.g. UTF-8) has to be converted into 7-bit clean ASCII for transport across the Internet. This function reverses the process. 87 | 88 | MIMEParser::ConvertFromRFC1342($data) 89 | ------------------------------------- 90 | 91 | Access: public static 92 | 93 | Parameters: 94 | 95 | * $data - A string containing the data to convert. 96 | 97 | Returns: A string containing the converted data. 98 | 99 | This static function converts RFC 1342 encoded header data into UTF-8 data. 8-bit headers have to be converted into 7-bit clean ASCII for transport across the Internet. This function reverses the process. 100 | 101 | MIMEParser::ConvertCharset($data, $incharset, $outcharset) 102 | ---------------------------------------------------------- 103 | 104 | Access: public static 105 | 106 | Parameters: 107 | 108 | * $data - A string containing the data to convert. 109 | * $incharset - A string containing the source character encoding. 110 | * $outcharset - A string containing the destination character encoding. 111 | 112 | Returns: A string containing the converted data if successful, a boolean of false on failure. 113 | 114 | This static function converts a string from one character set to another. Translation is done in the following order of preference: iconv(), mb_convert_encoding(), and then utf8_encode()/utf8_decode(). 115 | 116 | MIMEParser::ExplodeHeader($data) 117 | -------------------------------- 118 | 119 | Access: public static 120 | 121 | Parameters: 122 | 123 | * $data - A string containing a MIME header to parse. 124 | 125 | Returns: An array containing the parsed MIME header. 126 | 127 | This static function parses a single MIME header into its component pieces. The first piece's key is an empty string "". The rest are split up by key-value pairs. This function is called by `MIMEParser::Parse()` and `MIMEParser::ExtractContent()`. 128 | 129 | MIMEParser::Parse($data, $depth = 0) 130 | ------------------------------------ 131 | 132 | Access: public static 133 | 134 | Parameters: 135 | 136 | * $data - A string containing the MIME data to parse. 137 | * $depth - An internal integer to control recursive call depth (Default is 0). Do not use. 138 | 139 | Returns: An array containing the parsed MIME data. 140 | 141 | This static function parses MIME data into headers, body, and sub-MIME components. It recursively calls itself up to a depth of 10 to parse most MIME content. Do not use the `$depth` parameter when calling this function (second parameter). 142 | 143 | This function is typically used to parse an e-mail message retrieved from a POP3 server. This function can also handle non-MIME e-mail content. 144 | 145 | MIMEParser::ExtractContent($message, $depth = 0) 146 | ------------------------------------------------ 147 | 148 | Access: public static 149 | 150 | Parameters: 151 | 152 | * $message - An array from `MIMEParser::Parse()`. 153 | * $depth - An internal integer to control recursive call depth (Default is 0). Do not use. 154 | 155 | This function takes the output from `MIMEParser::Parse()` and extracts "text/plain" and "text/html" components from the message. It recursively calls itself up to a depth of 10 to parse the content. Do not use the `$depth` parameter when calling this function (second parameter). 156 | 157 | This function is typically used to extract just the text and HTML components of a MIME message that have been parsed by `MIMEParser::Parse()`. 158 | 159 | MIMEParser::ReplaceNewlines($replacewith, $data) 160 | ------------------------------------------------ 161 | 162 | Access: private static 163 | 164 | Parameters: 165 | 166 | * $replacewith - A string to replace newlines with. 167 | * $data - A string to replace newlines in. 168 | 169 | Returns: A string with newlines replaced. 170 | 171 | This static function replaces any newline combination within the input data with the target newline. All known (DOS, Mac, *NIX) and unknown newline combinations are handled to normalize on the replacement newline string. 172 | -------------------------------------------------------------------------------- /docs/pop3.md: -------------------------------------------------------------------------------- 1 | POP3 Class: 'support/pop3.php' 2 | =============================== 3 | 4 | The POP3 class provides routines to communicate with a POP3 server. These function are useful on servers that are configured to require "POP before SMTP" to send e-mail. They can also be used for automation of a script that watches a mailbox for incoming messages and then processes the incoming e-mail as it arrives. 5 | 6 | Example usage of POP before SMTP: 7 | 8 | ```php 9 | Your message goes here