ทำไมแยกเบราว์เซอร์แล้ว OTP ยังสลับกันได้?
จุดที่ต้องแยกคือเจ้าของคำขอ OTP ไม่ใช่แค่หน้าต่างเบราว์เซอร์ เมื่อทดสอบ OTP ด้วย Playwright ให้ออกแบบการแยกกล่องจดหมายและบัญชีทดสอบควบคู่กับการแยกเซสชัน อย่าถือว่าการสร้างบริบทเบราว์เซอร์ใหม่เป็นการจองทรัพยากรเหล่านั้นด้วย
สมมติว่างาน ก และงาน ข ใช้กล่องเดียวกัน ทั้งคู่ขอรหัสจากแอปเดียวกัน ผู้ส่งและหัวเรื่องจึงเหมือนกัน หากงาน ก อ่านหลังข้อความของงาน ข มาถึง การอ่าน “รหัสล่าสุด” ก็ไม่ได้บอกว่ารหัสนั้นเป็นของงาน ก
OTP คือรหัสผ่านแบบใช้ครั้งเดียว แต่คำว่าใช้ครั้งเดียวไม่ได้หมายความว่าตัวอ่านอีเมลจะจัดสรรรหัสให้แต่ละงานโดยอัตโนมัติ GET /mailboxes/{id}/otp ของ Mailera ใช้อ่าน OTP ล่าสุดของกล่องที่ระบุ และรองรับตัวกรอง from, subject, since_minutes ตัวกรองเหล่านี้ช่วยจำกัดการค้นหา ไม่ใช่กลไกจองกล่องหรือหลักฐานว่ารหัสเป็นของคำขอปัจจุบัน
Mailera เชื่อมกล่องจดหมายที่มีอยู่เข้ากับแอปผ่าน REST API หากยังไม่ได้เริ่มอ่านรหัสจากกล่องของคุณ ดูคู่มืออ่าน OTP จากกล่องจดหมายของตนเอง ก่อน ส่วนงานพร้อมกันควรเริ่มจากกติกานี้: หนึ่งกล่องมีเจ้าของงานที่กำลังขอ OTP ได้เพียงงานเดียว

ควรจัดสรรกล่องจดหมายให้แต่ละงานอย่างไร?
เตรียมรายการกล่องจดหมายทดสอบที่ทีมมีสิทธิ์ใช้งาน พร้อมบัญชีในแอปที่สัมพันธ์กับแต่ละกล่องก่อนเริ่มรัน จากนั้นเลือกขอบเขตการจองตามรูปแบบงาน ไม่จำเป็นต้องมีกล่องถาวรให้ทุกกรณีทดสอบ แต่ต้องไม่ให้คำขอที่ต้องแยกจากกันใช้กล่องเดียวกันในเวลาเดียวกัน
| วิธีจัดสรร | เหมาะกับกรณีใด | เงื่อนไขที่ต้องรักษา |
|---|---|---|
| จองกล่องต่อกรณีทดสอบ | แต่ละกรณีเริ่มและจบเป็นอิสระ | ถือสิทธิ์จนคำขอจบ ก่อนคืนให้กรณีถัดไป |
| จองกล่องต่อกระบวนการทดสอบ | ภายในกระบวนการรันทีละกรณี | ห้ามมีคำขอ OTP ซ้อนกันภายในกระบวนการนั้น |
| ใช้กล่องร่วมผ่านคิว | กล่องมีน้อยกว่างานที่รอ | ให้งานเดียวใช้กล่องในแต่ละช่วง งานอื่นต้องรอ |
สำหรับการทดสอบหลายเครื่อง ให้มีตัวจัดสรรกลางที่จองแบบอะตอมมิก กล่าวคือ เมื่อสองงานขอกล่องเดียวกันพร้อมกัน ต้องมีเพียงงานเดียวที่จองสำเร็จ อย่าให้แต่ละเครื่องอ่านรายการ “ว่าง” แล้วเลือกกล่องเองโดยไม่มีขั้นตอนยืนยันสิทธิ์ร่วมกัน
ในฝั่งตัวรันทดสอบ ควรเก็บความสัมพันธ์ต่อไปนี้ไว้ด้วยกัน:
- ตัวระบุรอบทดสอบและส่วนแบ่งงาน หรือ shard
- ตัวระบุกระบวนการทดสอบและกรณีทดสอบ
- ครั้งที่ลองใหม่
- รหัสกล่องจดหมายและบัญชีทดสอบ
- เจ้าของการจอง เวลาเริ่ม และเวลาหมดอายุการจอง
รายการนี้เป็นข้อมูลของตัวรันทดสอบ ไม่ใช่ฟิลด์ที่ต้องส่งให้ Mailera หมายเลขกระบวนการเพียงอย่างเดียวไม่ควรเป็นตัวระบุเจ้าของ ให้รวมบริบทของรอบและเครื่องที่รันด้วย เพื่อไม่ให้การเริ่มกระบวนการใหม่ถูกมองว่าเป็นงานเดิม
กำหนดอายุการจองเพื่อจัดการงานที่หยุดกลางทาง แต่เมื่อการจองหมดอายุ ให้ตรวจสถานะคำขอเดิมก่อนนำกล่องกลับมาใช้ การหมดสิทธิ์ของเจ้าของเดิมกับการสิ้นสุดคำขอ OTP ควรเป็นคนละสถานะในระบบจัดสรร
หากใช้ที่อยู่อีเมลแฝง ให้ตรวจว่าปลายทางเป็นกล่องแยกจริงหรือไม่ อย่านับจำนวนที่อยู่เป็นจำนวนกล่องที่แยกงานได้โดยอัตโนมัติ มาตรฐานรูปแบบข้อความอีเมล RFC 5322 แยก envelope ซึ่งมีข้อมูลที่จำเป็นสำหรับการส่งและนำส่ง ออกจากเนื้อหาข้อความ จึงควรตรวจปลายทางที่รับอีเมลจริงก่อนใช้ที่อยู่แฝงแบ่งงาน

หน้า กล่องจดหมาย ใช้ตรวจกล่องที่เชื่อมต่อและสถานะ ส่วนเจ้าของการจองกับคิวงานให้เก็บในตัวรันทดสอบ หากต้องเตรียมการเชื่อมต่อด้วยรหัสผ่านสำหรับแอป ดูแนวทางใช้ app password กับกล่องจดหมายสำหรับระบบอัตโนมัติ
อ่าน OTP ด้วย Mailera ตามลำดับใด?
แยกงานออกเป็นสองส่วนให้ชัด: ตัวรันทดสอบรับผิดชอบการจองและจับคู่คำขอ ส่วน Mailera รับผิดชอบการอ่านกล่องที่ระบุ ดูช่องทางเชื่อมต่อได้ที่หน้าสำหรับนักพัฒนา และรายละเอียดเส้นทางที่ใช้ด้านล่างในเอกสาร API
ตัวอย่างใช้ $MAILERA_API_KEY, $MAILBOX_ID และ $MESSAGE_ID ที่คุณตั้งจากสภาพแวดล้อมทดสอบของตนเอง คำสั่งอ่านอีเมลอาจแสดงข้อมูลลับในผลลัพธ์ จึงควรรันในเครื่องที่ควบคุมได้ ไม่วางคำสั่งเหล่านี้ลงในขั้นตอน CI ที่พิมพ์ผลตอบกลับทั้งหมดลงบันทึก
1. ตรวจรายการกล่อง แล้วจองกล่องพร้อมบัญชีทดสอบ
curl --silent --show-error \
'https://mailera.app/api/public/v1/mailboxes' \
-H "Authorization: Bearer $MAILERA_API_KEY"รายการกล่องอยู่ใน data โดยแต่ละรายการมี id, email, group_id และ status หากใช้กลุ่มสำหรับงานทดสอบ สามารถกรองรายการด้วย group_id ได้ จากนั้นให้ตัวจัดสรรเลือกกล่องที่อยู่ในรายการอนุญาตและยังไม่มีเจ้าของ
การเรียก GET /mailboxes เป็นการอ่านรายการ ไม่ใช่ขั้นตอนจอง งานต้องได้สิทธิ์จากตัวจัดสรรก่อนจึงค่อยขอให้แอปส่ง OTP
2. บันทึกบริบทก่อนขอรหัส
บันทึกเจ้าของการจอง ครั้งที่ลองใหม่ และเวลาเริ่มคำขอ จากนั้นให้แอปทดสอบส่ง OTP ไปยังกล่องที่จองไว้ พร้อมผูกเซสชันที่จะกรอกรหัสเข้ากับบริบทเดียวกัน
หากแอปของคุณมีตัวระบุธุรกรรม ให้เก็บไว้ในบริบทนี้ด้วย และออกแบบวิธีตรวจความสัมพันธ์กับอีเมล อย่าเพิ่มพารามิเตอร์ตัวระบุธุรกรรมลงในคำขอ Mailera เอง
3. อ่านจากกล่องที่จองไว้เท่านั้น
ตัวอย่างต่อไปนี้ใช้ผู้ส่งและหัวเรื่องสมมติ เปลี่ยนให้ตรงกับแอปทดสอบ ค่า since_minutes=5 เป็นเพียงค่าตัวอย่าง ไม่ใช่เวลารอมาตรฐานของทุกระบบ
curl --silent --show-error --get \
"https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/otp" \
-H "Authorization: Bearer $MAILERA_API_KEY" \
--data-urlencode 'from=no-reply@example.com' \
--data-urlencode 'subject=Test verification' \
--data-urlencode 'since_minutes=5'เส้นทางนี้ต้องใช้สิทธิ์ read ให้มองผลลัพธ์เป็นรหัสที่ต้องตรวจความสัมพันธ์กับงาน ไม่ใช่คำสั่งให้กรอกลงเบราว์เซอร์ทันที โดยเฉพาะเมื่อกล่องเพิ่งผ่านการลองใหม่หรือมีคำขอเก่าที่ยังไม่จบ
4. ตรวจข้อความต้นทางเมื่อจำเป็น
ใช้ GET /mailboxes/{id}/messages เพื่ออ่านรายการข้อความ เส้นทางนี้รองรับ since และ from รวมถึงตัวเลือกโฟลเดอร์ โดยตัวอย่างนี้อ่านจากกล่องขาเข้า:
curl --silent --show-error --get \
"https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/messages" \
-H "Authorization: Bearer $MAILERA_API_KEY" \
--data-urlencode 'folder=inbox' \
--data-urlencode 'from=no-reply@example.com'รายการข้อความใน data มี id, mailbox_id, from.address, to, subject และ received_at ใช้ข้อมูลเหล่านี้ตรวจกล่อง ผู้ส่ง ผู้รับ และช่วงเวลา แล้วนำ id ของข้อความที่ต้องตรวจมาตั้งเป็น $MESSAGE_ID
curl --silent --show-error \
"https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/messages/$MESSAGE_ID" \
-H "Authorization: Bearer $MAILERA_API_KEY"เนื้อหาข้อความอยู่ใน data.body.text และ data.body.html หากแอปส่งข้อมูลอ้างอิงคำขอไว้ในอีเมล ให้เทียบกับบริบทของงาน เวลา received_at ควรใช้เป็นเงื่อนไขประกอบ ไม่ใช่ตัวแทนของรหัสธุรกรรม
5. หยุดเมื่อแยกคำขอไม่ได้
หากมีหลายข้อความที่ตรงเงื่อนไข แต่ไม่มีข้อมูลพอจะระบุว่าข้อความใดเป็นของคำขอปัจจุบัน ให้จบงานด้วยผลลัพธ์ที่ระบุว่าแยกคำขอไม่ได้ เก็บข้อมูลวินิจฉัยโดยไม่เก็บรหัส อย่าเลือกข้อความล่าสุดแล้วลองกรอกไปก่อน
6. คืนกล่องเมื่อคำขอจบแล้ว
หลังยืนยันสำเร็จ หรือยกเลิกคำขอตามกติกาของแอป ให้ปิดบริบทและคืนกล่อง หากงานหมดเวลารอแต่คำขอยังค้าง ให้พักกล่องไว้เพื่อจัดการสถานะเดิมก่อน ไม่ส่งต่อให้งานใหม่ทันที
ลำดับที่ควรรักษาคือ จอง → ขอรหัส → อ่านและตรวจความสัมพันธ์ → ยืนยันหรือยุติคำขอ → คืนกล่อง การอ่านรหัสสำเร็จเพียงอย่างเดียวยังไม่ใช่จุดคืนกล่อง
จัดการการรออีเมลและการลองใหม่อย่างไร?
กำหนดเวลารอสูงสุดและระยะห่างระหว่างการตรวจไว้ในตัวรันทดสอบ เพิ่มการหน่วงแบบสุ่มเล็กน้อยเพื่อไม่ให้ทุกงานเรียก API เป็นจังหวะเดียวกัน เมื่อครบเวลารอให้หยุดพร้อมสาเหตุ ไม่วนอ่านต่อโดยไม่มีจุดสิ้นสุด
วางแผนงบคำขอ API รวมทุกงานที่ใช้คีย์เดียวกัน ไม่ใช่คำนวณแยกต่อกล่อง งบโดยประมาณสำหรับการตรวจซ้ำคือ:
คำขอต่อนาที ≈ จำนวนงานที่กำลังตรวจ × 60 ÷ ช่วงห่างการตรวจเป็นวินาที + คำขออื่นที่ใช้คีย์เดียวกัน
รวมการอ่านรายการกล่อง รายการข้อความ และเนื้อหาข้อความไว้ในงบด้วย แล้วเผื่อจำนวนคำขอไว้สำหรับการวินิจฉัยข้อผิดพลาด สูตรนี้ใช้วางแผนความถี่ ไม่ใช่ข้อสรุปว่าระบบของคุณควรรันพร้อมกันกี่งาน
แยก “อ่านอีเมลอีกครั้ง” ออกจาก “ขอ OTP ใหม่” ให้เป็นคนละการกระทำ การอ่านซ้ำควรตรวจคำขอเดิม ส่วนการขอใหม่ต้องเริ่มบริบทครั้งใหม่และจัดการคำขอก่อนหน้าตามนโยบายของแอป อย่าตั้งให้ระบบกดปุ่มส่งรหัสใหม่โดยอัตโนมัติทุกครั้งที่ไม่พบอีเมล
เมื่อทดสอบซ้ำ ให้ตรวจทั้งสิทธิ์การจองและคำขอค้างของครั้งก่อน การลดช่วงเวลาค้นหาอย่างเดียวไม่ควรเป็นวิธีป้องกันรหัสเก่า เพราะคุณยังต้องรับมือกรณีอีเมลของคำขอเดิมมาถึงหลังเริ่มรอบใหม่ด้วย หากยังแยกไม่ได้ ให้พักกล่องนั้นแล้วใช้อีกกล่องที่พร้อม หรือรอคิว
ถ้างานบางส่วนอยู่ใน reusable workflow ของ GitHub Actions ให้ตรวจการส่งคีย์เข้า workflow นั้นด้วย GitHub ระบุว่า secrets ไม่ถูกส่งต่อไปยัง reusable workflows โดยอัตโนมัติ แยกปัญหาการยืนยันตัวตนกับ API ออกจากปัญหาอีเมลยังไม่มาถึง เพื่อไม่ให้ตัวรันทดสอบรอผิดสาเหตุ
ข้อผิดพลาดที่พบบ่อยมีอะไรบ้าง?
| อาการ | จุดที่ควรตรวจ | แนวทางแก้ |
|---|---|---|
| รหัสสลับระหว่างงาน | หลายงานใช้กล่องเดียวกัน หรือค้นหาข้ามกล่อง | จองกล่องแบบมีเจ้าของ และระบุรหัสกล่องในเส้นทางอ่าน |
| ได้รหัสจากรอบก่อน | คำขอเดิมยังค้าง หรือคืนกล่องเร็วเกินไป | เริ่มบริบทใหม่ ตรวจคำขอเดิม และพักกล่องเมื่อยังแยกไม่ได้ |
| งานรอไม่จบ | ไม่มีเวลารอสูงสุด หรือสับสนระหว่าง API ล้มเหลวกับไม่พบข้อความ | แยกผลลัพธ์แต่ละแบบและกำหนดจุดหยุด |
| กล่องถูกจองค้าง | กระบวนการหยุดก่อนคืนกล่อง | ใช้เจ้าของและอายุการจอง พร้อมตรวจคำขอค้างก่อนคืนสู่คิว |
| คำขอ API มากเกินไป | แต่ละงานคุมความถี่แยกกัน แต่ใช้คีย์ร่วมกัน | คุมงบคำขอรวมและกระจายจังหวะตรวจ |
| เกิดปัญหาเฉพาะตอนรันหลายเครื่อง | ตัวระบุเจ้าของซ้ำ หรือการจองไม่เป็นอะตอมมิก | ใช้ตัวจัดสรรกลางและผูกเจ้าของกับรอบกับเครื่องที่รัน |
อย่าใช้ผู้ส่งเป็นตัวแยกงานเพียงอย่างเดียว และอย่าถือว่าข้อความที่ยังไม่อ่านเป็นข้อความของงานปัจจุบัน สถานะอ่านแล้วไม่ได้อธิบายความสัมพันธ์ระหว่างอีเมลกับคำขอ OTP
เช่นเดียวกัน อย่าใช้การทำเครื่องหมายว่าอ่านแล้วหรือการย้ายข้อความแทนการล็อกกล่อง ให้ระบบจองเป็นผู้ตัดสินสิทธิ์ใช้งาน ส่วนสถานะข้อความใช้จัดการอีเมลเท่านั้น
บันทึกที่เหมาะกับการหาสาเหตุควรมีตัวระบุรอบ กรณีทดสอบ ครั้งที่ลองใหม่ รหัสกล่อง เวลา และผลลัพธ์ หากต้องอ้างอิงข้อความ ให้เก็บรหัสข้อความแทนเนื้อหาเต็มฉบับ ไม่บันทึก OTP ลงใน log หรือชื่อไฟล์แนบของรายงานทดสอบ
ต้องปกป้องข้อมูลใด และ Mailera รับผิดชอบส่วนไหน?
ใช้เฉพาะกล่องจดหมายทดสอบที่คุณหรือทีมมีสิทธิ์เข้าถึง แยกจากกล่องส่วนตัวและข้อมูลผู้ใช้จริง ปิดบังที่อยู่อีเมล รหัส OTP และคีย์ในภาพหน้าจอ รวมถึงผลตอบกลับ API ที่อาจติดไปกับรายงานทดสอบ
ใน การตั้งค่า เลือก สร้าง API key แล้วจำกัด ขอบเขตกล่องจดหมาย ให้เป็นกลุ่มทดสอบ ให้คีย์มีเฉพาะสิทธิ์ read สำหรับงานอ่านรหัส ไม่เพิ่ม send หรือ manage เพียงเพื่อให้ชุดทดสอบอ่าน OTP ได้ ดูข้อมูลความปลอดภัยของ Mailera ประกอบการกำหนดสิทธิ์ของทีม

สำหรับ GitHub Actions ให้เก็บคีย์ใน secrets เท่านั้นและไม่พิมพ์ค่าลงบันทึก การไม่บันทึก OTP ตั้งแต่ต้นยังควรเป็นกติกาหลัก
Mailera ไม่รับประกันว่าอีเมลจะอยู่ในกล่องขาเข้า จึงควรแยกผลทดสอบแอปออกจากผลตรวจการรับอีเมล และกำหนดเวลารอในตัวรันทดสอบเอง ไม่ผูกความสำเร็จของงานไว้กับเวลาส่งถึงตายตัว
ส่วนการจองกล่อง การจัดคิว และการผูกรหัสกับธุรกรรม ให้ออกแบบในตัวรันทดสอบและแอป เส้นทางอ่าน OTP ใช้ดึงรหัสจากกล่องที่คุณระบุ ไม่ควรใช้แทนระบบควบคุมเจ้าของคำขอ
ทำสิ่งนี้ด้วย API
ทุกการดำเนินการในบทความนี้ทำได้ผ่าน REST API พร้อมตัวอย่าง curl, API key และ webhook
ดูเอกสาร API








