1<?php namespace Tx\Mailer; 2/***************************************************\ 3 * 4 * Mailer (https://github.com/txthinking/Mailer) 5 * 6 * A lightweight PHP SMTP mail sender. 7 * Implement RFC0821, RFC0822, RFC1869, RFC2045, RFC2821 8 * 9 * Support html body, don't worry that the receiver's 10 * mail client can't support html, because Mailer will 11 * send both text/plain and text/html body, so if the 12 * mail client can't support html, it will display the 13 * text/plain body. 14 * 15 * Create Date 2012-07-25. 16 * Under the MIT license. 17 * 18 \***************************************************/ 19class Message 20{ 21 /** 22 * from name 23 */ 24 protected $fromName; 25 26 /** 27 * from email 28 */ 29 protected $fromEmail; 30 31 /** 32 * fake from name 33 */ 34 protected $fakeFromName; 35 36 /** 37 * fake from email 38 */ 39 protected $fakeFromEmail; 40 41 /** 42 * to email 43 */ 44 protected $to = array(); 45 46 /** 47 * mail subject 48 */ 49 protected $subject; 50 51 /** 52 * mail body 53 */ 54 protected $body; 55 56 /** 57 *mail attachment 58 */ 59 protected $attachment = array(); 60 61 /** 62 * message header 63 */ 64 protected $header = array(); 65 66 /** 67 * charset 68 */ 69 protected $charset = "UTF-8"; 70 71 /** 72 * header multipart boundaryMixed 73 */ 74 protected $boundaryMixed; 75 76 /** 77 * header multipart alternative 78 */ 79 protected $boundaryAlternative; 80 81 /** 82 * $this->CRLF 83 * @var string 84 */ 85 protected $CRLF = "\r\n"; 86 87 /** 88 * set mail from 89 * @param string $name 90 * @param string $email 91 * @return $this 92 */ 93 public function setFrom($name, $email) 94 { 95 $this->fromName = $name; 96 $this->fromEmail = $email; 97 return $this; 98 } 99 100 101 /** 102 * set mail fake from 103 * @param string $name 104 * @param string $email 105 * @return $this 106 */ 107 public function setFakeFrom($name, $email) 108 { 109 $this->fakeFromName = $name; 110 $this->fakeFromEmail = $email; 111 return $this; 112 } 113 114 /** 115 * set mail receiver 116 * @param string $name 117 * @param string $email 118 * @return $this 119 */ 120 public function setTo($name, $email){ 121 $this->to[$name] = $email; 122 return $this; 123 } 124 125 /** 126 * add mail receiver 127 * @param string $name 128 * @param string $email 129 * @return $this 130 */ 131 public function addTo($name, $email){ 132 $this->to[$name] = $email; 133 return $this; 134 } 135 136 /** 137 * set mail subject 138 * @param string $subject 139 * @return $this 140 */ 141 public function setSubject($subject){ 142 $this->subject = $subject; 143 return $this; 144 } 145 146 /** 147 * set mail body 148 * @param string $body 149 * @return $this 150 */ 151 public function setBody($body){ 152 $this->body = $body; 153 return $this; 154 } 155 156 /** 157 * add mail attachment 158 * @param $name 159 * @param $path 160 * @return $this 161 */ 162 public function setAttachment($name, $path){ 163 $this->attachment[$name] = $path; 164 return $this; 165 } 166 167 /** 168 * add mail attachment 169 * @param $name 170 * @param $path 171 * @return $this 172 */ 173 public function addAttachment($name, $path){ 174 $this->attachment[$name] = $path; 175 return $this; 176 } 177 178 /** 179 * @return string 180 */ 181 public function getFromName() 182 { 183 return $this->fromName; 184 } 185 186 /** 187 * @return string 188 */ 189 public function getFromEmail() 190 { 191 return $this->fromEmail; 192 } 193 194 195 /** 196 * @return string 197 */ 198 public function getFakeFromName() 199 { 200 return $this->fakeFromName; 201 } 202 203 /** 204 * @return string 205 */ 206 public function getFakeFromEmail() 207 { 208 return $this->fakeFromEmail; 209 } 210 211 /** 212 * @return mixed 213 */ 214 public function getTo() 215 { 216 return $this->to; 217 } 218 219 /** 220 * @return mixed 221 */ 222 public function getSubject() 223 { 224 return $this->subject; 225 } 226 227 /** 228 * @return mixed 229 */ 230 public function getBody() 231 { 232 return $this->body; 233 } 234 235 /** 236 * @return array 237 */ 238 public function getAttachment() 239 { 240 return $this->attachment; 241 } 242 243 /** 244 * Create mail header 245 * @return $this 246 */ 247 protected function createHeader(){ 248 $this->header['Date'] = date('r'); 249 250 if(!empty($this->fakeFromEmail)){ 251 $this->header['Return-Path'] = $this->fakeFromEmail; 252 $this->header['From'] = $this->fakeFromName . " <" . $this->fakeFromEmail . ">"; 253 } else{ 254 $this->header['Return-Path'] = $this->fromEmail; 255 $this->header['From'] = $this->fromName . " <" . $this->fromEmail .">"; 256 } 257 258 $this->header['To'] = ''; 259 foreach ($this->to as $toName => $toEmail) { 260 $this->header['To'] .= $toName . " <" . $toEmail . ">, "; 261 } 262 $this->header['To'] = substr($this->header['To'], 0, -2); 263 $this->header['Subject'] = $this->subject; 264 $this->header['Message-ID'] = '<' . md5('TX'.md5(time()).uniqid()) . '@' . $this->fromEmail . '>'; 265 $this->header['X-Priority'] = '3'; 266 $this->header['X-Mailer'] = 'Mailer (https://github.com/txthinking/Mailer)'; 267 $this->header['MIME-Version'] = '1.0'; 268 if (!empty($this->attachment)){ 269 $this->boundaryMixed = md5(md5(time().'TxMailer').uniqid()); 270 $this->header['Content-Type'] = "multipart/mixed; \r\n\tboundary=\"" . $this->boundaryMixed . "\""; 271 } 272 $this->boundaryAlternative = md5(md5(time().'TXMailer').uniqid()); 273 return $this; 274 } 275 276 /** 277 * @brief createBody create body 278 * 279 * @return string 280 */ 281 protected function createBody(){ 282 $in = ""; 283 $in .= "Content-Type: multipart/alternative; boundary=\"$this->boundaryAlternative\"" . $this->CRLF; 284 $in .= $this->CRLF; 285 $in .= "--" . $this->boundaryAlternative . $this->CRLF; 286 $in .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->CRLF; 287 $in .= "Content-Transfer-Encoding: base64" . $this->CRLF; 288 $in .= $this->CRLF; 289 $in .= chunk_split(base64_encode($this->body)) . $this->CRLF; 290 $in .= $this->CRLF; 291 $in .= "--" . $this->boundaryAlternative . $this->CRLF; 292 $in .= "Content-Type: text/html; charset=\"" . $this->charset ."\"" . $this->CRLF; 293 $in .= "Content-Transfer-Encoding: base64" . $this->CRLF; 294 $in .= $this->CRLF; 295 $in .= chunk_split(base64_encode($this->body)) . $this->CRLF; 296 $in .= $this->CRLF; 297 $in .= "--" . $this->boundaryAlternative . "--" . $this->CRLF; 298 return $in; 299 } 300 301 /** 302 * @brief createBodyWithAttachment create body with attachment 303 * 304 * @return string 305 */ 306 protected function createBodyWithAttachment(){ 307 $in = ""; 308 $in .= $this->CRLF; 309 $in .= $this->CRLF; 310 $in .= '--' . $this->boundaryMixed . $this->CRLF; 311 $in .= "Content-Type: multipart/alternative; boundary=\"$this->boundaryAlternative\"" . $this->CRLF; 312 $in .= $this->CRLF; 313 $in .= "--" . $this->boundaryAlternative . $this->CRLF; 314 $in .= "Content-Type: text/plain; charset=\"" . $this->charset . "\"" . $this->CRLF; 315 $in .= "Content-Transfer-Encoding: base64" . $this->CRLF; 316 $in .= $this->CRLF; 317 $in .= chunk_split(base64_encode($this->body)) . $this->CRLF; 318 $in .= $this->CRLF; 319 $in .= "--" . $this->boundaryAlternative . $this->CRLF; 320 $in .= "Content-Type: text/html; charset=\"" . $this->charset ."\"" . $this->CRLF; 321 $in .= "Content-Transfer-Encoding: base64" . $this->CRLF; 322 $in .= $this->CRLF; 323 $in .= chunk_split(base64_encode($this->body)) . $this->CRLF; 324 $in .= $this->CRLF; 325 $in .= "--" . $this->boundaryAlternative . "--" . $this->CRLF; 326 foreach ($this->attachment as $name => $path){ 327 $in .= $this->CRLF; 328 $in .= '--' . $this->boundaryMixed . $this->CRLF; 329 $in .= "Content-Type: application/octet-stream; name=\"". $name ."\"" . $this->CRLF; 330 $in .= "Content-Transfer-Encoding: base64" . $this->CRLF; 331 $in .= "Content-Disposition: attachment; filename=\"" . $name . "\"" . $this->CRLF; 332 $in .= $this->CRLF; 333 $in .= chunk_split(base64_encode(file_get_contents($path))) . $this->CRLF; 334 } 335 $in .= $this->CRLF; 336 $in .= $this->CRLF; 337 $in .= '--' . $this->boundaryMixed . '--' . $this->CRLF; 338 return $in; 339 } 340 341 public function toString(){ 342 $in = ''; 343 $this->createHeader(); 344 foreach ($this->header as $key => $value) { 345 $in .= $key . ': ' . $value . $this->CRLF; 346 } 347 if (empty($this->attachment)) { 348 $in .= $this->createBody(); 349 } else { 350 $in .= $this->createBodyWithAttachment(); 351 } 352 $in .= $this->CRLF . $this->CRLF . "." . $this->CRLF; 353 return $in; 354 } 355 356} 357