diff --git a/GC_EmailAlert.md b/GC_EmailAlert.md new file mode 100644 index 0000000..5e98897 --- /dev/null +++ b/GC_EmailAlert.md @@ -0,0 +1,305 @@ +# Email Alert 架構分析 + +## 概述 + +RAIDGuard X 支援透過 SMTP 發送郵件通知功能,包括: +- 手動發送測試郵件 +- 事件觸發自動郵件通知 + +## 架構流程 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Email Alert 架構 │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ GUI │ │ Controller │ │ SMTP Server │ │ +│ │ frmEmail │◄──────►│ (Port 8922)│ │ │ │ +│ └──────┬───────┘ └──────────────┘ └──────┬───────┘ │ +│ │ │ │ +│ │ In-Band API (OpCode 0x01) │ │ +│ │ - SMTP 伺服器 │ │ +│ │ - SMTP 使用者名稱/密碼 │ │ +│ │ - 寄件人/收件人 │ │ +│ │ - 啟用事件通知 │ │ +│ └────────────────────────┬───────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ JavaMail API (javax.mail) │ │ +│ │ - Session.getInstance() │ │ +│ │ - MimeMessage │ │ +│ │ - Transport.send() │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +## 設定介面 (frmEmail) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Email Settings │ +├─────────────────────────────────────────────────────────────────┤ +│ Mailing List: [Send Test Email] │ +│ ┌─────────────────────────────────────────┐ │ +│ │ user1@example.com │ [Remove] │ +│ │ user2@example.com │ │ +│ │ │ │ +│ └─────────────────────────────────────────┘ │ +│ │ +│ SMTP Settings: │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ Mail Server (SMTP): [smtp.example.com ] │ │ +│ │ From Email: [sender@example.com ] │ │ +│ │ ☐ SMTP Auth Username: [__________] │ │ +│ │ Password: [__________] │ │ +│ │ ☐ Post Event to Email (Enable auto-alert) │ │ +│ └───────────────────────────────────────────────────────────┘ │ +│ │ +│ [OK] [Cancel] │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## 儲存的設定 + +透過 In-Band API 儲存到控制器: + +| OpCode | 說明 | +|--------|------| +| 0x07 | 更新 SMTP 伺服器名稱 | +| 0x09 | 更新 SMTP 使用者名稱 | +| 0x0A | 更新 SMTP 密碼 | +| 0x0B | 取得 SMTP 使用者名稱 | +| 0x0C | 取得 SMTP 密碼 | +| 0x05 | 取得 SMTP 伺服器名稱 | +| 0x0E | 儲存 Post Event 設定 | +| 0x19 | 取得 Post Event 設定 | + +## 程式碼分析 + +### 1. 郵件發送 (frmEmail.java) + +```java +// 使用 JavaMail API +import javax.mail.*; +import javax.mail.internet.*; + +public void jbSendMail_actionPerformed(ActionEvent e) { + // 建立 Session + Properties props = new Properties(); + props.put("mail.smtp.host", this.jtServerIp.getText()); + + if (jcSMTPCheck.isSelected()) { + // SMTP 認證 + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.user", sUsername); + props.put("mail.smtp.password", sPassword); + session = Session.getInstance(props, new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(sUsername, sPassword); + } + }); + } else { + // 無認證 + props.put("mail.smtp.auth", "false"); + session = Session.getInstance(props); + } + + // 建立郵件 + Message msg = new MimeMessage(session); + msg.setFrom(new InternetAddress(sNameMailFrom)); + msg.setSubject(sMailTitle); + msg.setText(sMailBody); + msg.setSentDate(new Date()); + + // 發送到所有收件人 + for (int j = 0; j < dmMailList.getRowCount(); j++) { + sNameMailTo = dmMailList.getValueAt(j, 0).toString().trim(); + if (!sNameMailTo.equals("")) { + msg.setRecipients(Message.RecipientType.TO, + InternetAddress.parse(sNameMailTo, false)); + Transport.send(msg); // 發送郵件 + } + } +} +``` + +### 2. SMTP 認證設定 + +```java +// 有認證 +if (jcSMTPCheck.isSelected()) { + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.ssl.enable", "true"); // SSL + session = Session.getInstance(props, new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); +} + +// 無認證 +else { + props.put("mail.smtp.host", smtpServer); + props.put("mail.smtp.auth", "false"); + session = Session.getInstance(props); +} +``` + +### 3. 事件通知開關 + +```java +// 儲存 Post Event 設定到控制器 +bCmds[2] = 0x0E; // OpCode + +if (jcPostEvent.isSelected()) { + bCmds[4] = 1; // Enable +} else { + bCmds[4] = 0; // Disable +} + +// 透過 CmdQueue 發送到控制器 +CmdQueue.NewCommand(ip, sn, 1, 1, 0x01); +``` + +## 依賴庫 + +```xml + + + com.sun.mail + javax.mail + 1.6.2 + +``` + +## Polling 與事件觸發 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Polling Timer (定時輪詢) │ +│ - wkPolling1: 每 12 秒 │ +│ - wkPolling2: 每 30 秒 │ +│ - wkEventPolling: 每 18 秒 │ +│ - wkEventPollingForSNMP: 每 22 秒 │ +└──────────────────────────┬──────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 檢測事件 │ +│ 1. 取得控制器事件 (Page 0x24) │ +│ 2. 比對新事件 │ +│ 3. 觸發通知 │ +└──────────────────────────┬──────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 通知方式 │ +│ - SNMP Trap (frmMain.EventPollingForSNMP) │ +│ - Email Alert (如果 jcPostEvent 啟用) │ +│ - UI Event List 更新 │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## 關鍵類 + +| 類別 | 檔案 | 功能 | +|------|------|------| +| `frmEmail` | frmEmail.java | 郵件設定介面 | +| `dlgServer` | dlgServer.java | Server 設定 (包含 SMTP) | +| `PageDataDB` | PageDataDB.java | 郵件設定儲存 | +| `SNMPSender` | SNMP/SNMPSender.java | SNMP Trap 發送 | + +## Code Flow + +### 1. 設定 SMTP +``` +frmEmail (開啟) + → 輸入 SMTP 伺服器 + → 輸入寄件人/收件人 + → (可選) 啟用 SMTP 認證 + → (可選) 啟用 Post Event + → OK → 儲存到控制器 (OpCode 0x07/0x09/0x0A/0x0E) +``` + +### 2. 發送測試郵件 +``` +點擊 [Send Test Email] + → frmEmail.jbSendMail_actionPerformed() + → 建立 Session (JavaMail) + → 發送到所有收件人 + → 顯示成功/失敗訊息 +``` + +### 3. 事件自動通知 +``` +Polling 偵測到新事件 + → 檢查 jcPostEvent 是否啟用 + → 組建郵件內容 (事件描述) + → 發送到所有收件人 +``` + +## 郵件格式 + +``` +Subject: RAIDGuard X Alert - {Controller Name} + +Body: +Controller: {SN} +Event: {Event Description} +Time: {Timestamp} +Severity: {Info/Warning/Error} +``` + +## 安全考量 + +1. **密碼儲存**: SMTP 密碼儲存在控制器端,可能有安全風險 +2. **傳輸加密**: 支援 SSL/TLS (jcSMTPCheck) +3. **認證**: 支援 SMTP AUTH (PLAIN/LOGIN) + +## Rust 實作建議 + +```rust +// 使用 lettre crate +use lettre::{SmtpClient, Transport, Message, SendableEmail}; +use lettre::smtp::authentication::Credentials; + +pub fn send_email( + smtp_server: &str, + username: &str, + password: &str, + from: &str, + to: &str, + subject: &str, + body: &str, + use_auth: bool, + use_tls: bool, +) -> Result<(), Box> { + + let email = Message::builder() + .from(from.parse()?) + .to(to.parse()?) + .subject(subject) + .body(body.to_string())?; + + let mut smtp = SmtpClient::new_localhost()?; + + if use_tls { + smtp = SmtpClient::new_new_ssl(smtp_server)?; + } else { + smtp = SmtpClient::new_new(smtp_server)?; + } + + if use_auth { + let creds = Credentials::new(username.to_string(), password.to_string()); + smtp = smtp.credentials(creds); + } + + let mut transport = smtp.transport(); + transport.send(email)?; + + Ok(()) +} +```