application/
├── config/
│ └── email.php # 郵件配置文件
├── helpers/
│ └── email_helper.php # 封裝發送函數
├── libraries/
│ └── PHPMailer/ # PHPMailer 庫文件
│ ├── class.phpmailer.php
│ ├── class.smtp.php
│ └── class.pop3.php
application/config/email.php<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$config['mail_protocol'] = 'smtp';
$config['mail_smtp_host'] = 'smtp.21cn.com';
$config['mail_smtp_port'] = 25; // 465 (SSL) / 587 (TLS)
$config['mail_smtp_user'] = 'xxxx@21cn.com';
$config['mail_smtp_pass'] = 'your_password';
$config['mail_from_email'] = 'xxxx@21cn.com';
$config['mail_from_name'] = '焦常雲';
$config['mail_charset'] = 'UTF-8';
$config['mail_mailtype'] = 'html';
$config['mail_newline'] = "\r\n";
$config['mail_smtp_crypto'] = ''; // 'ssl' 或 'tls'
$config['mail_smtp_timeout'] = 30;
application/helpers/email_helper.php<?php
defined('BASEPATH') OR exit('No direct script access allowed');
if (!function_exists('send_email')) {
/**
* 發送郵件統一入口
* @param string|array $to 收件人,支持單個或多個
* @param string $subject 主題
* @param string $message 內容(HTML)
* @param array $options 附加選項:cc, bcc, attachments 等
* @return bool
*/
function send_email($to, $subject, $message, $options = []) {
$CI =& get_instance();
// 載入配置
$CI->config->load('email', TRUE);
$cfg = $CI->config->item('email');
// 載入 PHPMailer
require_once APPPATH . 'libraries/PHPMailer/class.phpmailer.php';
require_once APPPATH . 'libraries/PHPMailer/class.smtp.php';
$mail = new PHPMailer(true); // 啟用異常拋出
try {
// 基礎設置
$mail->isSMTP();
$mail->Host = $cfg['mail_smtp_host'];
$mail->Port = $cfg['mail_smtp_port'];
$mail->SMTPAuth = true;
$mail->Username = $cfg['mail_smtp_user'];
$mail->Password = $cfg['mail_smtp_pass'];
$mail->CharSet = $cfg['mail_charset'];
$mail->Encoding = 'base64';
// 加密協議
if (!empty($cfg['mail_smtp_crypto'])) {
$mail->SMTPSecure = $cfg['mail_smtp_crypto'];
}
// 超時設置
$mail->Timeout = $cfg['mail_smtp_timeout'];
// 發件人
$mail->setFrom($cfg['mail_from_email'], $cfg['mail_from_name']);
// 收件人
$recipients = is_array($to) ? $to : [$to];
foreach ($recipients as $recipient) {
$mail->addAddress($recipient);
}
// 抄送/密送
if (!empty($options['cc'])) {
foreach ((array)$options['cc'] as $cc) $mail->addCC($cc);
}
if (!empty($options['bcc'])) {
foreach ((array)$options['bcc'] as $bcc) $mail->addBCC($bcc);
}
// 附件
if (!empty($options['attachments'])) {
foreach ((array)$options['attachments'] as $attachment) {
if (is_array($attachment)) {
$mail->addAttachment($attachment['path'], $attachment['name'] ?? '');
} else {
$mail->addAttachment($attachment);
}
}
}
// 郵件內容
$mail->isHTML($cfg['mail_mailtype'] === 'html');
$mail->Subject = $subject;
$mail->Body = $message;
$mail->AltBody = strip_tags($message); // 純文本備選
// 發送
$mail->send();
log_message('info', "Email sent to: " . implode(',', $recipients));
return true;
} catch (phpmailerException $e) {
log_message('error', "PHPMailer Error: " . $e->errorMessage());
} catch (Exception $e) {
log_message('error', "Email Send Error: " . $e->getMessage());
}
return false;
}
}
<?php
class Welcome extends CI_Controller {
public function test_email() {
$this->load->helper('email');
$result = send_email(
'user@example.com',
'測試郵件主題',
'你好!
這是一封HTML測試郵件。
',
[
'cc' => 'admin@example.com',
'attachments' => [
['path' => FCPATH . 'uploads/report.pdf', 'name' => '月報.pdf'],
]
]
);
echo $result ? '發送成功' : '發送失敗,請查看日誌';
}
}
// 將郵件任務推送到隊列
function queue_email($to, $subject, $message, $options = []) {
$CI =& get_instance();
$CI->load->library('queue'); // 假設使用 Redis/RabbitMQ 隊列庫
$CI->queue->push('email_job', compact('to', 'subject', 'message', 'options'));
}
// Worker 處理
class EmailJob {
public function perform($data) {
send_email($data['to'], $data['subject'], $data['message'], $data['options']);
}
}
function send_template_email($to, $template, $data, $subject) {
$CI =& get_instance();
$message = $CI->load->view('emails/' . $template, $data, TRUE);
return send_email($to, $subject, $message);
}
// 視圖文件:application/views/emails/welcome.php
// 歡迎 = $username ?>!
// 數據庫表:email_logs (to, subject, status, attempts, last_error, created_at)
// 發送前寫入記錄,失敗時更新 attempts 和 last_error,定時任務重試 attempts < 3 的記錄
| 錯誤現象 | 排查方向 |
|---|---|
| SMTP connect() failed | 主機/端口錯誤、防火牆攔截、SSL/TLS 協議不匹配 |
| Authentication failed | 賬號密碼錯誤、需開啟「客戶端授權碼」(如 QQ 郵箱、Gmail) |
| 中文亂碼 | CharSet 未設置 UTF-8、Subject 需用 mb_encode_mimeheader |
| 大附件發送失敗 | 調整 PHP memory_limit、post_max_size、SMTP 服務商限制 |
.env 或環境變量注入SMTPSecure = 'tls')