setTo()、setCC()、setBCC()、setFrom()、setSubject()、setText()、setHTML()、setAttachments()、send()<?php
class Email {
public $mailTo = ''; public $mailCC = ''; public $mailBCC = '';
public $mailFrom = ''; public $mailSubject = '';
public $mailText = ''; public $mailHTML = ''; public $mailAttachments = '';
// 共用地址驗證
private function checkEmail($addr) {
return (bool)preg_match('/^[^@]+@([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/', $addr);
}
public function setTo($addr) {
foreach (explode(',', $addr) as $a) if (!$this->checkEmail(trim($a))) return false;
$this->mailTo = implode(',', array_map('trim', explode(',', $addr)));
return true;
}
// setCC, setBCC, setFrom, setSubject, setText, setHTML, setAttachments 類似...
// MIME 組裝核心
private function getRandomBoundary($offset=0) {
srand(time() + $offset);
return "----" . md5(rand());
}
private function getContentType($file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
$map = [
'gif'=>'image/gif', 'jpg'=>'image/jpeg', 'jpeg'=>'image/jpeg',
'png'=>'image/png', 'txt'=>'text/plain', 'html'=>'text/html',
'htm'=>'text/html', 'zip'=>'application/zip', 'gz'=>'application/gzip',
'pdf'=>'application/pdf',
];
return $map[$ext] ?? 'application/octet-stream';
}
public function send() {
$headers = "";
if ($this->mailCC) $headers .= "CC: {$this->mailCC}\r\n";
if ($this->mailBCC) $headers .= "BCC: {$this->mailBCC}\r\n";
if ($this->mailFrom) $headers .= "From: {$this->mailFrom}\r\n";
// 純文字
if ($this->mailText && !$this->mailHTML && !$this->mailAttachments) {
return mail($this->mailTo, $this->mailSubject, $this->mailText, $headers);
}
// 文字 + HTML (multipart/alternative)
if ($this->mailText && $this->mailHTML && !$this->mailAttachments) {
$boundary = $this->getRandomBoundary();
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/alternative; boundary=\"$boundary\"\r\n\r\n";
$body = "--$boundary\r\n";
$body .= "Content-Type: text/plain; charset=utf-8\r\n\r\n{$this->mailText}\r\n";
$body .= "--$boundary\r\n";
$body .= "Content-Type: text/html; charset=utf-8\r\n\r\n{$this->mailHTML}\r\n";
$body .= "--$boundary--";
return mail($this->mailTo, $this->mailSubject, $body, $headers);
}
// 文字 + HTML + 附件 (multipart/mixed)
if ($this->mailText && $this->mailHTML && $this->mailAttachments) {
$outer = $this->getRandomBoundary();
$inner = $this->getRandomBoundary(1);
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"$outer\"\r\n\r\n";
$headers .= "This is a multi-part message in MIME format.\r\n";
$headers .= "--$outer\r\n";
$headers .= "Content-Type: multipart/alternative; boundary=\"$inner\"\r\n\r\n";
$headers .= "--$inner\r\n";
$headers .= "Content-Type: text/plain; charset=utf-8\r\n\r\n{$this->mailText}\r\n";
$headers .= "--$inner\r\n";
$headers .= "Content-Type: text/html; charset=utf-8\r\n\r\n{$this->mailHTML}\r\n";
$headers .= "--$inner--\r\n";
foreach (explode(',', $this->mailAttachments) as $file) {
$file = trim($file);
$headers .= "--$outer\r\n";
$ctype = $this->getContentType($file);
$headers .= "Content-Type: $ctype; name=\"".basename($file)."\"\r\n";
$headers .= "Content-Transfer-Encoding: base64\r\n";
$headers .= "Content-Disposition: attachment; filename=\"".basename($file)."\"\r\n\r\n";
$content = chunk_split(base64_encode(file_get_contents($file)));
$headers .= $content . "\r\n";
}
$headers .= "--$outer--";
return mail($this->mailTo, $this->mailSubject, "", $headers);
}
return false;
}
}
?>
<?php
require 'Email.php';
$mail = new Email();
$mail->setTo("user@example.com");
$mail->setCC("cc1@example.com, cc2@example.com");
$mail->setBCC("bcc@example.com");
$mail->setFrom("system@example.com");
$mail->setSubject("測試郵件");
$mail->setText("這是純文字內容");
$mail->setHTML("<h1>這是<b>HTML</b>內容</h1>");
$mail->setAttachments("/path/to/file.pdf, /path/to/image.png");
if ($mail->send()) echo "寄送成功";
else echo "寄送失敗";
?>
mail() 依賴本地 MTA,易被視為垃圾郵件;生產環境建議改用 PHPMailer、Symfony Mailer、Laravel Mail 等透過 SMTP (含 SSL/TLS、認證) 發送。base64_encode() 而非外部 uuencode,跨平台相容性更好。此類別完整實作 MIME 多部分郵件組裝,涵蓋文字、HTML、附件、抄送/密送,適合教學理解郵件結構。實務專案請採用成熟郵件庫並配置可靠 SMTP 伺服器。