306 lines
13 KiB
Markdown
306 lines
13 KiB
Markdown
# 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
|
|
<!-- pom.xml -->
|
|
<dependency>
|
|
<groupId>com.sun.mail</groupId>
|
|
<artifactId>javax.mail</artifactId>
|
|
<version>1.6.2</version>
|
|
</dependency>
|
|
```
|
|
|
|
## 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<dyn std::error::Error>> {
|
|
|
|
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(())
|
|
}
|
|
```
|