Add Email Alert architecture analysis
This commit is contained in:
@@ -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
|
||||
<!-- 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(())
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user