1. ภาพรวม
Mail Proxy คือ HTTP API ภายในองค์กรสำหรับส่งอีเมลแจ้งเตือนจากระบบต่าง ๆ เช่น Wazuh, LibreNMS, script และ n8n โดยระบบต้นทางไม่ต้องมีรหัสผ่าน SMTP ใช้แค่ API key ของตัวเอง ซึ่งเพิกถอนหรือจำกัดอัตราการส่งแยกรายระบบได้
| ส่วนประกอบ | หน้าที่ |
|---|---|
| API | ตรวจ API key, rate limit, template แล้วส่งต่อไป SMTP relay |
| SMTP relay | Postfix ส่งต่อไป Gmail ผ่าน STARTTLS |
| Key store | Redis เก็บ API key แบบ SHA-256, ตัวนับ rate limit, สถิติ 30 วัน |
| Edge | Cloudflare Tunnel (ไม่มีพอร์ตเปิดสู่อินเทอร์เน็ตโดยตรง) |
2. Features ที่รองรับ
X-RateLimit-*to เป็น string หรือ array และมี cc, bcc"html": true (เฉพาะ /send)sender_name แสดงชื่อ เช่น "ระบบงานตรวจสอบ" (รองรับ UTF-8)GET /health รายงานสถานะ Redis และ SMTP3. ผู้ดูแลระบบ: จัดการ API key
mpkey บนเครื่องที่รัน key store ของระบบ (ต้องมีสิทธิ์ผู้ดูแล)ผู้ใช้งานทั่วไป: ขอ API key จากผู้ดูแลระบบ โดยแจ้งชื่อระบบ, rate ที่ต้องการ, อายุ key, template ที่ใช้ และอีเมลผู้รับผิดชอบ (ใช้รับ key และรับแจ้งเมื่อ key ถูกปิด เปิด หรือลบ)
3.1 สร้าง key
# mpkey create <name> [rate_per_min=60] [expire_days=0] [templates=*] [--mail <email>]
mpkey create wazuh-prod 100 # 100 ครั้ง/นาที, ไม่หมดอายุ
mpkey create n8n-sit 30 90 # 30 ครั้ง/นาที, หมดอายุใน 90 วัน
mpkey create zimbra-mon 20 0 zimbra,system # ใช้ได้เฉพาะ template zimbra และ system
mpkey create batch-job 0 # ไม่จำกัด rate (ใช้เท่าที่จำเป็น)
mpkey create app-x 60 0 --mail owner@example.com # ผูกอีเมลเจ้าของ + ส่ง key ทางอีเมล
| Parameter | ค่าเริ่มต้น | ความหมาย |
|---|---|---|
name | (ต้องใส่) | ชื่อระบบที่ใช้ key ห้ามมีอักขระ < > & " |
rate_per_min | 60 | จำนวน request ต่อนาที · 0 = ไม่จำกัด |
expire_days | 0 | อายุ key เป็นวัน · 0 = ไม่หมดอายุ |
templates | * | template ที่อนุญาต คั่นด้วย comma |
--mail <email> | — | อีเมลเจ้าของ key (วางตำแหน่งไหนก็ได้ รองรับ --mail=addr) ระบบตรวจรูปแบบอีเมลก่อนสร้าง |
ผลลัพธ์:
name=app-x rate=60/min expires=never templates=* email=owner@example.com hash=3f9c0a1b7e2d
API KEY (shown once): mp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
mail sent to owner@example.com
3.2 การส่ง key ให้ผู้ใช้: เลือกวิธีตามความเสี่ยง
| วิธี | เหมาะกับ | ข้อควรระวัง |
|---|---|---|
A. --mail ส่งอีเมลอัตโนมัติ | ผู้ใช้เป็นคน เช่น ทีมพัฒนาหรือผู้รับเหมา ที่ต้องการคู่มือไปด้วย | key อยู่ในกล่องจดหมายของผู้รับเป็นข้อความธรรมดา ใช้ได้เฉพาะอีเมลองค์กรหรือที่เชื่อถือได้ · แนะนำให้ผู้รับย้าย key ไป vault แล้วลบเมล |
| B. Pipe ตรงเข้าไฟล์ บนเครื่องปลายทาง | ระบบอัตโนมัติ เช่น cron, watchdog หรือ agent | ปลอดภัยที่สุด key ไม่แสดงบนจอเลยmpkey create app-x 60 | sed -n 's/^API KEY (shown once): /X-API-Key: /p' | ssh host 'umask 077; cat > /etc/app-x.key' |
| C. คัดลอกเข้า vault ด้วยมือ | ระบบที่อ่าน secret จาก vault หรือ secret manager | ห้ามวาง key ในแชท, ticket หรือ Git |
วิธี B/C ใช้ร่วมกับ --mail ได้ ถ้าต้องการผูกอีเมลเจ้าของไว้รับแจ้งเตือน แต่ไม่อยากให้ key ไปอยู่ในอีเมล ให้สร้างแบบไม่ใส่ --mail (ตอนนี้ยังไม่มีคำสั่งผูกอีเมลภายหลัง ดู 3.6)
3.3 อีเมลที่ระบบส่งอัตโนมัติ
| เหตุการณ์ | Subject | เนื้อหา |
|---|---|---|
create --mail | [Mail Proxy] API key สำหรับ <name> | API key, hash อ้างอิง, rate limit, วันหมดอายุ, template, endpoint, ตัวอย่าง curl, ลิงก์คู่มือ และคำเตือนเรื่องการเก็บรักษา |
disable | [Mail Proxy] API key "<name>" disabled | เวลาที่ปิด และบอกว่าจะได้ HTTP 401 API_KEY_DISABLED |
enable | [Mail Proxy] API key "<name>" enabled | เวลาที่เปิด และบอกว่าใช้งานได้ตามปกติ |
delete | [Mail Proxy] API key "<name>" deleted | เวลาที่ลบ และแนะนำให้ขอ key ใหม่ (HTTP 401 INVALID_API_KEY) |
ผู้ส่งแสดงเป็น Mail Proxy Admin · อีเมลแจ้ง disable/enable/delete ไม่มีค่า key · key ที่ไม่ได้ผูกอีเมลจะไม่มีการส่งเมลใด ๆ
ถ้าส่งเมลไม่สำเร็จ คำสั่งยังมีผลตามปกติ แต่จะขึ้น WARN: mail to … FAILED ให้ผู้ดูแลแจ้งเจ้าของเองทางช่องทางอื่น
3.4 ดูรายการ, ปิด/เปิด, ลบ
mpkey list
HASH NAME ENABLED RATE EXPIRES LAST_USED EMAIL
3f9c0a1b7e2d app-x true 60 never 2026-09-27T16:55:24 owner@example.com
7b21d0c94a5e backup-cron true 10 never -
mpkey disable 3f9c # ปิดชั่วคราว มีผลทันที + แจ้งเจ้าของ (ใส่แค่ต้นของ hash ที่ไม่ซ้ำกับตัวอื่นก็พอ)
mpkey enable 3f9c # เปิดคืน + แจ้งเจ้าของ
mpkey delete 3f9c # ลบถาวร + แจ้งเจ้าของ
ถ้า hash prefix ตรงกับ key 0 ตัวหรือมากกว่า 1 ตัว คำสั่งจะหยุดโดยไม่แก้ไขอะไร
3.5 Mapping อีเมล และ audit log
| ที่เก็บ | เนื้อหา | อายุข้อมูล |
|---|---|---|
Redis mailproxy:apikey:<hash> field email | อีเมลเจ้าของของ key ที่ยังอยู่ (ดูได้จาก mpkey list) | ลบไปพร้อม key · Redis เปิด AOF ไว้แล้ว |
| Audit log บนเครื่องผู้ดูแล | 1 บรรทัดต่อ action: เวลา, action, ผู้สั่ง, hash, ชื่อ, อีเมล · ไม่มีค่า key | เก็บถาวร ยังอยู่แม้ key ถูกลบ |
# ประวัติของ key ใด key หนึ่ง / ของเจ้าของคนหนึ่ง
grep 'hash=3f9c' <audit log>
grep 'email=owner@example.com' <audit log>
2026-09-27T17:56:50+0700 create by=admin hash=3f9c0a1b7e2d name=app-x email=owner@example.com rate=60 expires=never templates=*
2026-09-27T17:56:53+0700 disable by=admin hash=3f9c0a1b7e2d name=app-x email=owner@example.com
3.6 ข้อจำกัดของ mpkey
- ยังไม่มีคำสั่งเปลี่ยนหรือผูกอีเมลให้ key ที่สร้างไปแล้ว ต้องสร้าง key ใหม่ด้วย
--mailแล้วลบ key เดิม - ยังไม่มีคำสั่ง rotate ต้องใช้ create ใหม่ → ให้ผู้ใช้เปลี่ยน key → delete เดิม
- ไม่มีการแจ้งเตือนก่อน key หมดอายุ และไม่ส่งเมลตอน key หมดอายุ
- ผูกอีเมลได้ 1 ที่อยู่ต่อ key ถ้าต้องการให้หลายคนรับ ให้ใช้อีเมลกลุ่ม
3.7 แนวทางตั้งชื่อและค่า
| หัวข้อ | แนวทาง |
|---|---|
| ชื่อ key | <ระบบ>-<env> เช่น wazuh-prod หรือ n8n-sit 1 ระบบใช้ 1 key เพื่อให้เพิกถอนแยกกันได้ |
| rate limit | alert ทั่วไปใช้ 10–60/นาที ระบบที่อาจยิงถี่ (SIEM) ใช้ 100 ไม่ควรตั้ง 0 ถ้าไม่จำเป็น |
| วันหมดอายุ | key ทดสอบหรือของผู้รับเหมาให้ตั้งเสมอ เช่น 1–90 วัน |
| ขอบเขต template | ระบบที่ใช้ template เดียวให้จำกัดไว้ เช่น wazuh |
4. API Reference
Base URL: https://mailproxy.ipv9.me · ยืนยันตัวตนด้วย header X-API-Key: mp_... · ส่งข้อมูลเป็น Content-Type: application/json
| Method | Path | Auth | คำอธิบาย |
|---|---|---|---|
| GET | /health | — | สถานะระบบ: healthy หรือ degraded |
| POST | /api/v1/send | ✔ | ส่งอีเมลโดยกำหนด subject และ body เอง |
| POST | /api/v1/send/template | ✔ | ส่งอีเมลด้วย template |
| GET | /api/v1/templates | ✔ | รายการ template และ field ที่ต้องใช้ (ใช้ทดสอบ key ได้โดยไม่ส่งเมล) |
| GET | /docs, /redoc, /openapi.json | — | เอกสาร API แบบโต้ตอบ |
POST /api/v1/send: request body
| Field | Type | ต้องใส่ | คำอธิบาย |
|---|---|---|---|
to | string | string[] | ✔ | ผู้รับ 1 คนหรือหลายคน (ระบบตรวจรูปแบบอีเมลให้) |
subject | string | ✔ | ห้ามว่าง ระบบตัดช่องว่างหัวท้ายให้ |
body | string | ✔ | เนื้อหา plain text หรือ HTML |
html | bool | true = ส่งเป็น text/html (ค่าเริ่มต้น false) | |
sender_name | string | ชื่อที่แสดงในช่อง From | |
from_addr | ค่าเริ่มต้นคือบัญชี relay ขององค์กร (ดูข้อจำกัดในหัวข้อ 8) | ||
cc, bcc | string[] | สำเนา / สำเนาลับ |
Response (HTTP 200)
{
"success": true,
"message_id": "ef8ce787-3faa-46c2-961e-daf7a64001c1",
"timestamp": "2026-09-27T09:58:08.681369",
"recipient": "user@example.com",
"template": null,
"error": null
}
Response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (unix time ที่ตัวนับจะเริ่มใหม่) · header Message-ID ของอีเมลคือ <message_id@mailproxy.ipv9.me> ใช้ค้นย้อนหลังได้
5. ตัวอย่างการใช้งาน
ทุกตัวอย่างอ่าน key จาก environment variable MAILPROXY_KEY หรือจากไฟล์ ห้ามเขียน key ลงในโค้ดโดยตรง
ส่งแบบพื้นฐาน
curl -sS -X POST https://mailproxy.ipv9.me/api/v1/send \
-H "X-API-Key: $MAILPROXY_KEY" -H 'Content-Type: application/json' \
-d '{"to":"user@example.com","subject":"Test","body":"Hello from Mail Proxy"}'
หลายผู้รับ + CC/BCC + ชื่อผู้ส่ง
curl -sS -X POST https://mailproxy.ipv9.me/api/v1/send \
-H "X-API-Key: $MAILPROXY_KEY" -H 'Content-Type: application/json' \
-d '{
"to": ["ops1@example.com","ops2@example.com"],
"cc": ["lead@example.com"],
"bcc": ["audit@example.com"],
"sender_name": "ระบบงานตรวจสอบ",
"subject": "สรุปผลตรวจประจำวัน",
"body": "ผ่าน 42 รายการ / ไม่ผ่าน 0 รายการ"
}'
HTML body
curl -sS -X POST https://mailproxy.ipv9.me/api/v1/send \
-H "X-API-Key: $MAILPROXY_KEY" -H 'Content-Type: application/json' \
-d '{"to":"user@example.com","subject":"Report","html":true,
"body":"<h2>Daily report</h2><p style=\"color:#1a7f37\">All systems OK</p>"}'
อ่าน key จากไฟล์ (key ไม่อยู่ใน argv และไม่โผล่ใน ps)
# /etc/myapp.key (0600) มี 1 บรรทัด: X-API-Key: mp_...
curl -sS -X POST https://mailproxy.ipv9.me/api/v1/send -H @/etc/myapp.key \
-H 'Content-Type: application/json' -d @payload.json
Script แจ้งเตือนเมื่อคำสั่งล้มเหลว (ใช้กับ cron ได้)
#!/bin/sh
# usage: notify-on-fail.sh <command...> — ส่งเมลเมื่อ command จบด้วย exit ≠ 0
out=$("$@" 2>&1); rc=$?
[ $rc -eq 0 ] && exit 0
payload=$(python3 -c 'import json,sys,socket
print(json.dumps({"to":"ops@example.com","sender_name":"Cron Monitor",
"subject":f"[FAIL] {socket.gethostname()}: {sys.argv[1]} (rc={sys.argv[2]})",
"body":sys.argv[3][-4000:]}))' "$*" "$rc" "$out")
curl -sS --max-time 30 -X POST https://mailproxy.ipv9.me/api/v1/send \
-H @/etc/notify.key -H 'Content-Type: application/json' -d "$payload" \
| grep -q '"success":true' || logger -t notify "mailproxy send failed"
exit $rc
ใช้ใน crontab: 0 2 * * * /usr/local/bin/notify-on-fail.sh /opt/backup/run.sh
Python (requests) พร้อม retry เมื่อโดน 429 หรือ 503
import os, time, requests
URL = "https://mailproxy.ipv9.me/api/v1/send"
HDR = {"X-API-Key": os.environ["MAILPROXY_KEY"]}
def send_mail(to, subject, body, html=False, retries=3, **extra):
payload = {"to": to, "subject": subject, "body": body, "html": html, **extra}
for attempt in range(retries):
r = requests.post(URL, json=payload, headers=HDR, timeout=30)
if r.status_code == 200:
return r.json()["message_id"]
if r.status_code == 429: # rate limited
time.sleep(int(r.headers.get("Retry-After", 60)))
elif r.status_code == 503: # SMTP relay error
time.sleep(2 ** attempt * 5)
else: # 401/403/422: ไม่ต้อง retry
raise RuntimeError(f"{r.status_code}: {r.text}")
raise RuntimeError("mailproxy: retries exhausted")
send_mail(["a@example.com", "b@example.com"], "Backup done", "OK",
sender_name="Backup Bot", cc=["lead@example.com"])
Python stdlib (ไม่ต้องติดตั้ง package)
import json, os, urllib.request
req = urllib.request.Request(
"https://mailproxy.ipv9.me/api/v1/send/template",
data=json.dumps({
"to": "ops@example.com",
"template": "system",
"sender_name": "Disk Monitor",
"data": {"hostname": os.uname().nodename, "alert_type": "Disk usage",
"severity": "WARNING", "message": "/var at 91%"}
}).encode(),
headers={"X-API-Key": os.environ["MAILPROXY_KEY"], "Content-Type": "application/json"},
)
print(json.load(urllib.request.urlopen(req, timeout=30)))
Node.js 18+ (ใช้ fetch ที่มีในตัว)
const res = await fetch("https://mailproxy.ipv9.me/api/v1/send", {
method: "POST",
headers: { "X-API-Key": process.env.MAILPROXY_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
to: ["dev@example.com"],
subject: `Deploy ${process.env.APP_VERSION} finished`,
body: "Deploy succeeded",
html: true,
sender_name: "CI/CD",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json(), "remaining:", res.headers.get("x-ratelimit-remaining"));
PHP (cURL)
<?php
$ch = curl_init('https://mailproxy.ipv9.me/api/v1/send');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('MAILPROXY_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'to' => 'user@example.com',
'subject' => 'แจ้งเตือนจากระบบ',
'body' => 'ข้อความภาษาไทยรองรับ UTF-8',
'sender_name' => 'ระบบสารสนเทศ',
], JSON_UNESCAPED_UNICODE),
]);
$resp = json_decode(curl_exec($ch), true);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($code !== 200) { error_log("mailproxy $code: " . json_encode($resp)); }
PowerShell (Windows)
$body = @{
to = @("helpdesk@example.com")
subject = "[Windows] $env:COMPUTERNAME service stopped"
body = (Get-Service Spooler | Out-String)
sender_name = "Windows Monitor"
} | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri "https://mailproxy.ipv9.me/api/v1/send" `
-Headers @{ "X-API-Key" = $env:MAILPROXY_KEY } `
-ContentType "application/json; charset=utf-8" `
-Body ([System.Text.Encoding]::UTF8.GetBytes($body))
n8n: HTTP Request node
| ค่า | ตั้งเป็น |
|---|---|
| Method / URL | POST · https://mailproxy.ipv9.me/api/v1/send |
| Authentication | Generic Credential → Header Auth · Name X-API-Key · Value = key (เก็บเป็น credential ของ n8n ไม่ใส่ใน node) |
| Body | JSON: |
{
"to": "{{ $json.email }}",
"subject": "Ticket #{{ $json.id }} updated",
"body": "{{ $json.summary }}",
"sender_name": "Service Desk"
}
ตั้ง Options → Retry On Fail = 3 และ Wait Between Tries = 60000 ms เพื่อรองรับกรณีโดน 429
6. Templates
| template | Subject ที่ได้ | Field ที่ต้องใส่ | Field เสริม |
|---|---|---|---|
wazuh | [Wazuh Alert] {level}: {rule_description} | level, rule_id, rule_description, agent_name, agent_ip | full_log, timestamp |
zimbra | [Zimbra Alert] {alert_type}: {summary} | alert_type, summary | details, timestamp |
system | [System Alert] {hostname}: {alert_type} | hostname, alert_type, severity, message | timestamp |
custom | {subject} | subject, body | — |
ถ้าไม่ส่ง timestamp ระบบจะใส่เวลาปัจจุบัน (Asia/Bangkok) ให้
curl -sS -X POST https://mailproxy.ipv9.me/api/v1/send/template \
-H "X-API-Key: $MAILPROXY_KEY" -H 'Content-Type: application/json' \
-d '{
"to": "soc@example.com",
"template": "wazuh",
"sender_name": "Wazuh SIEM",
"data": {
"level": 12, "rule_id": "100409", "rule_description": "MISP threat IP on web",
"agent_name": "web-01", "agent_ip": "192.0.2.10",
"full_log": "GET /wp-login.php from 203.0.113.9"
}
}'
7. Error codes
| HTTP | code | สาเหตุ | สิ่งที่ client ควรทำ |
|---|---|---|---|
| 401 | INVALID_API_KEY | ไม่ส่ง header หรือ key ไม่ถูกต้อง | ตรวจ key ห้าม retry |
| 401 | API_KEY_DISABLED | ผู้ดูแลปิด key นี้ไว้ | ติดต่อผู้ดูแล |
| 401 | API_KEY_EXPIRED | key หมดอายุแล้ว | ขอ key ใหม่ |
| 403 | TEMPLATE_NOT_ALLOWED | key นี้ไม่ได้รับสิทธิ์ใช้ template นี้ | ใช้ template ที่ได้รับอนุญาต |
| 400 | MISSING_TEMPLATE_DATA | field ที่ template ต้องใช้ขาดหรือว่าง | เติม field ตามข้อความ error |
| 422 | (validation) | JSON ผิดรูปแบบ, อีเมลไม่ถูกต้อง, subject/body ว่าง | แก้ payload |
| 429 | RATE_LIMIT_EXCEEDED | เกินโควตาของนาทีนี้ | รอตาม header Retry-After แล้วค่อยส่งใหม่ |
| 503 | SMTP_ERROR | ส่งต่อไป Postfix ไม่สำเร็จ | retry แบบ backoff และตรวจ /health |
| 530 / 1033 | (Cloudflare) | tunnel ไม่มี connector ทำงานอยู่ | แจ้งผู้ดูแล |
รูปแบบ error: {"detail":{"code":"RATE_LIMIT_EXCEEDED","message":"...","retry_after":42}}
8. ข้อจำกัดของระบบ
| หัวข้อ | ข้อจำกัด |
|---|---|
| ไฟล์แนบ | ไม่รองรับ ส่งได้แค่ text หรือ HTML ถ้าจำเป็นให้ใส่เป็นลิงก์ดาวน์โหลดแทน |
| multipart/alternative | ส่งได้ทีละแบบ คือ plain หรือ HTML ไม่มี text สำรองในฉบับ HTML · /send/template เป็น plain text เสมอ |
| ความหมายของ "success" | success:true แปลว่า Postfix รับเมลเข้าคิวแล้ว ยังไม่ได้แปลว่าถึงกล่องผู้รับ ถ้าปลายทางตีกลับหรือ Gmail ปฏิเสธ client จะไม่รู้ ต้องดู log ของ mailrelay |
| ผู้ส่ง (From) | ส่งผ่านบัญชี Gmail ขององค์กร ถ้ากำหนด from_addr เป็นอีเมลอื่น Gmail อาจเขียน From ทับเป็นบัญชีที่ใช้ login เว้นแต่ address นั้นตั้งเป็น "Send mail as" ไว้ในบัญชี · sender_name ใช้ได้เสมอ |
| โควตาการส่ง | อยู่ภายใต้โควตาของ Google Workspace ของบัญชี relay (ประมาณ 2,000 ฉบับ/วัน และนับผู้รับแต่ละคน) ถ้าเกิน Gmail จะหยุดส่งชั่วคราว ไม่ควรใช้ส่งจดหมายข่าวหรือ bulk mail |
| Rate limit | นับแบบ fixed window ต่อนาทีปฏิทิน ต่อ key ตอนขึ้นนาทีใหม่อาจส่งได้เกินชั่วคราวสูงสุด 2 เท่า · request ที่ผ่านการตรวจ key แล้วถูกนับทุกครั้ง รวมถึงที่จบด้วย 400/403/503 (ส่วน 401 และ 422 ไม่นับ) · GET /templates ไม่นับ |
| Idempotency | ไม่มี ถ้า client retry หลัง timeout ทั้งที่รอบแรกส่งสำเร็จแล้ว ผู้รับจะได้เมลซ้ำ |
| High availability | SMTP relay และ key store รันแบบ instance เดียว ถ้าเครื่องที่รันล่ม ระบบจะส่งเมลไม่ได้และ auth ไม่ได้จนกว่าเครื่องจะกลับมา · API มี 1 instance |
| ขนาด | Postfix จำกัดขนาดเมล 50 MB แต่แนะนำให้ body ไม่เกินหลักร้อย KB |
| การจัดการ key | ไม่มี admin API หรือ UI ผู้ดูแลจัดการผ่าน mpkey · สถิติเก็บ 30 วัน · การแจ้งเตือนทางอีเมลขึ้นกับ Mail Proxy เอง ถ้าระบบล่มจะไม่มีเมลแจ้ง |
| Endpoint สาธารณะ | /health และ /docs เปิดให้ทุกคนเข้าได้ · CORS อนุญาตทุก origin ดังนั้นห้ามเรียก API จาก JavaScript ฝั่ง browser เพราะ key จะหลุด |
9. Operations (ผู้ดูแลระบบ)
ผู้ใช้งานตรวจสถานะได้เองที่
GET https://mailproxy.ipv9.me/health (healthy = พร้อมใช้งาน)10. แนวปฏิบัติด้านความปลอดภัย
- 1 ระบบใช้ 1 key · เก็บใน secret manager, vault หรือไฟล์ 0600 · ส่ง key ด้วย
curl -H @fileเพื่อไม่ให้โผล่ในps - ตั้งวันหมดอายุให้ key ชั่วคราว · จำกัด template ให้แคบที่สุดเท่าที่ใช้
- ตรวจ
mpkey listเป็นระยะ ปิด key ที่ไม่มีLAST_USEDนานเกิน 90 วัน - ผูกอีเมลเจ้าของ (
--mail) ให้ทุก key เพื่อให้ติดต่อได้เมื่อต้องปิด key · ถ้าได้รับ key ทางอีเมล ให้ย้ายเข้า vault แล้วลบเมลทันที
- ใส่ key ใน source code, Git, ข้อความแชท, ticket หรือ JavaScript ฝั่ง browser
- ใช้ key เดียวร่วมกันหลายระบบ เพราะจะเพิกถอนแยกไม่ได้
- ส่ง key ด้วย
--mailไปยังอีเมลส่วนตัว, forwarder หรือกล่องที่หลายคนเข้าถึงได้ - ใส่ข้อมูลลับหรือข้อมูลส่วนบุคคลใน body โดยไม่จำเป็น เพราะเมลผ่าน Gmail และ log ของ relay
ถ้าสงสัยว่า key หลุด: mpkey disable <hash> ทันที (เจ้าของได้รับเมลแจ้ง) → mpkey create … --mail <เจ้าของ> สร้าง key ใหม่ → mpkey delete key เดิม