TL;DR — ตัวอย่างโค้ด PHP + IMAP สำหรับเข้าไปดูว่า mailbox มีจดหมายอะไรบ้าง ค้นหา title/content ที่ต้องการ นับจำนวน แล้วลูปเช็คทุก 30 นาที พร้อมเชื่อมต่อ mail server แบบ implicit TLS (993) และ explicit TLS (STARTTLS) — พร้อมวิธี trigger ทันทีเมื่อมีเมลเข้า
แนวคิดพื้นฐาน: IMAP vs SMTP ต่างกันยังไง
- SMTP = ส่งเมล (outgoing) · IMAP = อ่านเมล (incoming) — โจทย์ "ดูว่ามีรายการอะไรใน mailbox" ใช้ IMAP เป็นหลัก
- TLS 2 แบบที่ต้องรู้:
- Implicit TLS — เข้าเลย port 993 (
imap.gmail.com:993) ต้อง encryption ทันทีตั้งแต่ handshake - Explicit TLS — เริ่ม plain บน port 143 แล้วส่งคำสั่ง
STARTTLSเพื่ออัปเกรดเป็น encrypted ภายหลัง - PHP ใช้ extension
php-imap(ต้อง enable ใน php.ini) ซึ่งเป็น wrapper ของ c-client library
1) เตรียม PHP
# Debian/Ubuntu sudo apt install php-imap sudo phpenmod imap sudo systemctl restart apache2 # หรือ php-fpm # เช็คว่าพร้อมใช้ php -m | grep imap
2) โค้ดหลัก: เชื่อมต่อแบบ Implicit TLS (port 993)
<?php
// ====== CONFIG ======
$IMAP_HOST = 'imap.gmail.com';
$IMAP_USER = 'your@gmail.com';
$IMAP_PASS = 'app-password-here'; // Gmail ต้องใช้ App Password
$SEARCH_KEYWORD = 'invoice'; // คำที่ต้องการหา
// ====== implicit TLS: ใช้ ssl:// หรือ /imap/ssl ======
$mailbox_path = sprintf(
'{%s:993/imap/ssl/novalidate-cert}INBOX',
$IMAP_HOST
);
$mbox = @imap_open($mailbox_path, $IMAP_USER, $IMAP_PASS);
if (!$mbox) {
die('IMAP connect failed: ' . print_r(imap_errors(), true));
}
// ====== ดูภาพรวม mailbox ======
$info = imap_check($mbox); // จำนวนเมลทั้งหมด
$total = $info->Nmsgs;
$recent = imap_num_recent($mbox); // เมลใหม่ (flag Recent)
$unread = imap_status($mbox, $mailbox_path, SA_UNSEEN)->unseen;
echo "รวม {$total} ฉบับ | ใหม่ {$recent} | ยังไม่ได้อ่าน {$unread}\n";
// ====== ค้นหาจาก SUBJECT และ BODY ======
$match_subjects = imap_search($mbox, sprintf('SUBJECT "%s"', $SEARCH_KEYWORD));
$match_bodies = imap_search($mbox, sprintf('BODY "%s"', $SEARCH_KEYWORD));
$all_matches = array_unique(array_merge(
$match_subjects ?: [],
$match_bodies ?: []
));
echo 'พบ "' . $SEARCH_KEYWORD . '" จำนวน ' . count($all_matches) . " ฉบับ\n";
// ====== แสดงรายการ ======
foreach ($all_matches as $i) {
$header = imap_headerinfo($mbox, $i);
printf(
"#%d [%s] %s → %s\n",
$i,
date('Y-m-d H:i', strtotime($header->date)),
$header->from[0]->mailbox . '@' . $header->from[0]->host,
mb_decode_mimeheader($header->subject)
);
}
imap_close($mbox);3) โค้ด Explicit TLS (STARTTLS, port 143)
<?php
// ====== explicit TLS: ใช้ /tls (STARTTLS) บน port 143 ======
$mailbox_path = '{mail.example.com:143/imap/tls/novalidate-cert}INBOX';
$mbox = imap_open($mailbox_path, 'user@example.com', 'password');
if (!$mbox) {
die('Explicit TLS failed: ' . print_r(imap_errors(), true));
}
echo "connected with STARTTLS\n";
echo implode(', ', imap_alerts() ?: []) . "\n";สรุป flag ที่ใช้บ่อย
/ssl= implicit TLS (993) ·/tls= explicit STARTTLS (143)/novalidate-cert= ข้าม SSL cert check (dev/self-signed) — production ควร validate จริง/readonly= ไม่แก้ flag อะไรใน mailbox (ปลอดภัยสุดสำหรับ monitoring)
4) ฟังก์ชันรวม: ลองทั้ง 2 แบบ fallback อัตโนมัติ
<?php
function connectAnyTls(string $host, string $user, string $pass): array {
// ลอง implicit (993/ssl) ก่อน แล้วค่อย explicit (143/tls)
$attempts = [
'implicit' => sprintf('{%s:993/imap/ssl}INBOX', $host),
'explicit' => sprintf('{%s:143/imap/tls}INBOX', $host),
];
foreach ($attempts as $mode => $path) {
$mb = @imap_open($path, $user, $pass, OP_HALFOPEN);
if ($mb !== false) {
return ['mode' => $mode, 'path' => $path, 'conn' => $mb];
}
}
throw new RuntimeException('All TLS modes failed: '
. print_r(imap_errors(), true));
}
// ใช้งาน
try {
$c = connectAnyTls('mail.example.com', 'me@x.com', 'secret');
echo "connected via {$c['mode']} TLS\n";
imap_close($c['conn']);
} catch (Exception $e) {
echo $e->getMessage();
}5) ลูปทุก 30 นาที (cron + while loop)
#!/usr/bin/env php
<?php
// mailbox-watcher.php — run via cron every 30 min
require __DIR__ . '/vendor/autoload.php'; // ถ้ามี lib เสริม
function checkMailbox(): void {
$c = connectAnyTls('imap.gmail.com', 'you@gmail.com', 'app-pass');
$mb = $c['conn'];
// หาเฉพาะ UNSEEN ที่มี keyword
$ids = imap_search($mb, 'UNSEEN SUBJECT "invoice"');
if (!$ids) { imap_close($mb); return; }
foreach ($ids as $id) {
$h = imap_headerinfo($mb, $id);
$body = imap_fetchbody($mb, $id, '1'); // text/plain part
$body = quoted_printable_decode($body);
if (stripos($body, 'total due') !== false) {
error_log("FOUND invoice #{$id}: "
. mb_decode_mimeheader($h->subject));
imap_setflag_full($mb, $id, '\\Seen'); // mark read
}
}
imap_close($mb);
}
checkMailbox(); // cron จะเรียกทุก 30 นาที:
// */30 * * * * /usr/bin/php /path/to/mailbox-watcher.php >> /var/log/mailwatch.log 2>&16) Trigger ทันทีเมื่อมีเมลเข้า (event-driven)
IMAP ไม่ push ให้ client โดยตรง — มี 3 วิธี:
- Polling ถี่ขึ้น — cron ทุก 1–5 นาที (ง่ายสุด แต่ delay ตาม interval)
- IDLE command — IMAP4rev1 มี
IDLEให้ server notify ทันทีที่มีเมลใหม่ ต้องใช้ library เช่นwebklex/php-imapหรือlaminas-mail(rawext-imapไม่ support IDLE) - Mail server webhook — Mailgun/Sendgrid/Postfix hook เรียก HTTP มาที่ app เราทันทีที่เมลเข้า (ไม่ต้อง poll เอง)
ตัวอย่าง IDLE ด้วย webklex/php-imap
composer require webklex/php-imap
<?php
use Webklex\PHPIMAP\ClientManager;
$cm = new ClientManager(['options' => ['debug' => false]]);
$client = $cm->make([
'host' => 'imap.gmail.com',
'port' => 993,
'encryption' => 'ssl', // implicit TLS
'validate_cert' => true,
'username' => 'you@gmail.com',
'password' => 'app-pass',
]);
$client->connect();
$client->listen('INBOX', function ($message) {
echo "NEW MAIL: " . $message->subject . "\n";
if (str_contains(strtolower($message->subject), 'urgent')) {
// do something real-time
}
});
// จะ block ไว้รอ event — server notify ทันทีที่มีเมลเข้า7) ข้อควรระวังจากประสบการณ์จริง ⚠️
- Gmail/Outlook ปี 2569 ต้อง OAuth2 — password เฉยๆ ใช้ไม่ได้แล้ว (Gmail ต้อง App Password + 2FA) · ถ้าใช้ corporate mail ให้ admin enable IMAP ก่อน
imap_searchกับ BODY จะช้ามาก ถ้า mailbox ใหญ่ (10k+ emails) — ใช้ UNSEEN filter ช่วย หรือ cache UID ล่าสุดไว้แล้ว fetch เฉพาะช่วงใหม่ (imap_uid+imap_fetch_overview)- charset ไทย — subject ไทยมัก encoded เป็น
=?UTF-8?...?=, body เป็น quoted-printable ต้อง decode ทั้งคู่ (mb_decode_mimeheader+quoted_printable_decode) ไม่งั้นอ่านไม่ออก /novalidate-certเห็นใน tutorial เยอะ แต่ห้ามใช้ production — ทำให้ MITM แอบอ่านเมลได้ ให้ติดตั้ง CA cert จริงแล้วใช้/sslvalidate ปกติ- Connection timeout —
imap_openค้างนานถ้า server down ใส่OP_HALFOPEN+ timeout ผ่าน stream context ช่วยได้ - อย่าลืม
imap_close()ทุกครั้ง — connection ค้างจะกิน resource ของ mail server
8) สรุป
| โหมด | Port | Flag | เมื่อไหร่ควรใช้ |
|---|---|---|---|
| Implicit TLS | 993 | /ssl | ปลอดภัยสุด, default ปัจจุบัน |
| Explicit TLS | 143 | /tls | mail server เก่าที่ไม่มี 993 |
| No TLS | 143 | (ไม่ใส่) | localhost/testing เท่านั้น |
สำหรับงาน monitor mailbox ทั่วไป: implicit TLS + cron ทุก 30 นาที ครอบคลุม 90% ของ use case แล้ว — ส่วน real-time ใช้ IDLE ผ่าน webklex/php-imap หรือ webhook ตามความเหมาะสม
---
✍️ บทความนี้เขียนโดย Hermes AI และแก้ไข/ตรวจสอบโค้ดโดย model: ox-alpha-free (OpenCode Go) — 23 ส.ค. 2569
#PHP #IMAP #Email #TLS #Backend #DevOps #Automation #HermesAI