header[$name][] = $value; } public function env_from($value) { $this->env_from = $value; } protected function contentType($path) { if (($fh = popen('/usr/bin/file -i -b ' . escapeshellarg(realpath($path)), 'r')) !== false) { $type = fread($fh, 1024); fclose($fh); $parts = explode(';', $type); return trim($parts[0]); } else return mime_content_type($file); } public function attach($content, $type=false, $first=false) { $part = new stdClass(); if ($type === false) { if (file_exists($content)) { $part->content = chunk_split(base64_encode(file_get_contents($content))); $part->header = 'Content-Type: ' . $this->contentType($content) . '; name="'.basename($content).'"'. $this->CRLF . 'Content-Transfer-Encoding: base64' . $this->CRLF . 'Content-Disposition: attachment'; } } elseif (substr($type, 0, 10) == 'text/plain' || substr($type, 0, 9) == 'text/html') { if (strpos($type, 'charset=') === false) $type .= '; charset="UTF-8"'; $part->content = $content; $part->header = 'Content-Type: ' . $type . $this->CRLF . 'Content-Transfer-Encoding: 8bit'; } else { $part->content = chunk_split(base64_encode($content)); $part->header = 'Content-Type: ' . $type . $this->CRLF . 'Content-Transfer-Encoding: base64' . $this->CRLF . 'Content-Disposition: attachment'; } if (!empty($part->content)) { if ($first) array_unshift($this->attachments, $part); else $this->attachments[] = $part; } } public function send($body=false) { if (!array_key_exists('From', $this->header)) throw new Exception('No sender given.'); if (!array_key_exists('To', $this->header)) throw new Exception('No recipient given.'); if (!array_key_exists('Subject', $this->header)) throw new Exception('No subject given.'); if (!count($this->attachments) && empty($body)) throw new Exception('Mail body empty and no attachments.'); if (count($this->attachments)) { $boundary = md5(uniqid(time())); $this->header['MIME-Version'] = array('1.0'); $this->header['Content-Type'] = array('multipart/mixed; boundary="'.$boundary.'"'); if ($body) $this->attach($body, substr($body,0,1) == '<' ? 'text/html' : 'text/plain', true); } else { if (!array_key_exists('Content-Type', $this->header)) { if ($body && substr($body,0,1) == '<') $this->set('Content-Type', 'text/html; charset=UTF-8'); else $this->set('Content-Type', 'text/plain; charset=UTF-8'); } if (!array_key_exists('Content-Disposition', $this->header)) $this->set('Content-Disposition', 'inline'); if (!array_key_exists('Content-Transfer-Encoding', $this->header)) $this->set('Content-Transfer-Encoding', '8bit'); } $header = ''; $to = implode(', ', $this->header['To']); if (defined('MAIL_DISABLED') && MAIL_DISABLED !== false) { $header .= 'Orig-To: ' . $to . $this->CRLF; $to = MAIL_DISABLED; if (array_key_exists('Cc', $this->header)) { $this->header['Orig-Cc'] = $this->header['Cc']; unset($this->header['Cc']); } if (array_key_exists('Bcc', $this->header)) { $this->header['Orig-Bcc'] = $this->header['Bcc']; unset($this->header['Bcc']); } } foreach ($this->header as $name => $values) { if ($name == 'To' || $name == 'Subject') continue; else $header .= $name . ': ' . implode(', ', $values) . $this->CRLF; } $opts = '-t'; $opts .= strlen($this->env_from) ? ' -f '.$this->env_from : ''; $header = substr($header,0,-strlen($this->CRLF)); if (count($this->attachments)) { $header .= $this->CRLF . "This is a MIME encoded message." . $this->CRLF; foreach ($this->attachments as $part) { $header .= "--$boundary" . $this->CRLF; $header .= $part->header . $this->CRLF; $header .= $this->CRLF . $part->content . $this->CRLF; } $header .= "--$boundary--"; $result = mail($to, $this->header['Subject'][0], '', $header, $opts); } else { $result = mail($to, $this->header['Subject'][0], $body, $header, $opts); } Application::debug(sprintf('Send Mail "%s" to %s', $this->header['Subject'][0], $this->header['To'][0])); return $result; } }