---
title: "ทดสอบ OTP ทางอีเมลพร้อมกันอย่างไรไม่ให้รหัสสลับกัน"
description: "วิธีจองกล่องจดหมายให้แต่ละงาน อ่าน OTP ผ่าน API ของ Mailera และจัดคิวเมื่อกล่องไม่พอ พร้อมรับมืออีเมลล่าช้าและการลองใหม่"
url: https://mailera.app/th/blog/parallel-email-otp-tests
published: 2026-10-25
updated: 2026-10-25
---

# ทดสอบ OTP ทางอีเมลพร้อมกันอย่างไรไม่ให้รหัสสลับกัน

แยกกล่องจดหมายให้แต่ละงาน จองก่อนขอรหัส และคืนเมื่อคำขอจบจริง เพราะรหัสล่าสุดในกล่องไม่ได้แปลว่าเป็นรหัสของงานที่กำลังอ่าน

## ทำไมแยกเบราว์เซอร์แล้ว OTP ยังสลับกันได้?

จุดที่ต้องแยกคือเจ้าของคำขอ OTP ไม่ใช่แค่หน้าต่างเบราว์เซอร์ เมื่อทดสอบ OTP ด้วย Playwright ให้ออกแบบการแยกกล่องจดหมายและบัญชีทดสอบควบคู่กับการแยกเซสชัน อย่าถือว่าการสร้างบริบทเบราว์เซอร์ใหม่เป็นการจองทรัพยากรเหล่านั้นด้วย

สมมติว่างาน ก และงาน ข ใช้กล่องเดียวกัน ทั้งคู่ขอรหัสจากแอปเดียวกัน ผู้ส่งและหัวเรื่องจึงเหมือนกัน หากงาน ก อ่านหลังข้อความของงาน ข มาถึง การอ่าน “รหัสล่าสุด” ก็ไม่ได้บอกว่ารหัสนั้นเป็นของงาน ก

OTP คือรหัสผ่านแบบใช้ครั้งเดียว แต่คำว่าใช้ครั้งเดียวไม่ได้หมายความว่าตัวอ่านอีเมลจะจัดสรรรหัสให้แต่ละงานโดยอัตโนมัติ `GET /mailboxes/{id}/otp` ของ Mailera ใช้อ่าน OTP ล่าสุดของกล่องที่ระบุ และรองรับตัวกรอง `from`, `subject`, `since_minutes` ตัวกรองเหล่านี้ช่วยจำกัดการค้นหา ไม่ใช่กลไกจองกล่องหรือหลักฐานว่ารหัสเป็นของคำขอปัจจุบัน

[Mailera เชื่อมกล่องจดหมายที่มีอยู่เข้ากับแอปผ่าน REST API](https://mailera.app/th/product) หากยังไม่ได้เริ่มอ่านรหัสจากกล่องของคุณ ดู[คู่มืออ่าน OTP จากกล่องจดหมายของตนเอง](https://mailera.app/th/blog/email-otp-api) ก่อน ส่วนงานพร้อมกันควรเริ่มจากกติกานี้: **หนึ่งกล่องมีเจ้าของงานที่กำลังขอ OTP ได้เพียงงานเดียว**

![งานทดสอบสองชุดจองกล่องจดหมายแยกกันผ่านตัวจัดสรร ก่อนอ่าน OTP ไปใช้ในเซสชันของตน](https://mailera.app/media/43425f10a8f87c85/otp-parallel-mailbox-flow-th-1200.jpg)
_แยกเจ้าของกล่องก่อนขอรหัส ตัวจัดสรรอยู่ในฝั่งตัวรันทดสอบ_

## ควรจัดสรรกล่องจดหมายให้แต่ละงานอย่างไร?

เตรียมรายการกล่องจดหมายทดสอบที่ทีมมีสิทธิ์ใช้งาน พร้อมบัญชีในแอปที่สัมพันธ์กับแต่ละกล่องก่อนเริ่มรัน จากนั้นเลือกขอบเขตการจองตามรูปแบบงาน ไม่จำเป็นต้องมีกล่องถาวรให้ทุกกรณีทดสอบ แต่ต้องไม่ให้คำขอที่ต้องแยกจากกันใช้กล่องเดียวกันในเวลาเดียวกัน

| วิธีจัดสรร | เหมาะกับกรณีใด | เงื่อนไขที่ต้องรักษา |
| --- | --- | --- |
| จองกล่องต่อกรณีทดสอบ | แต่ละกรณีเริ่มและจบเป็นอิสระ | ถือสิทธิ์จนคำขอจบ ก่อนคืนให้กรณีถัดไป |
| จองกล่องต่อกระบวนการทดสอบ | ภายในกระบวนการรันทีละกรณี | ห้ามมีคำขอ OTP ซ้อนกันภายในกระบวนการนั้น |
| ใช้กล่องร่วมผ่านคิว | กล่องมีน้อยกว่างานที่รอ | ให้งานเดียวใช้กล่องในแต่ละช่วง งานอื่นต้องรอ |

สำหรับการทดสอบหลายเครื่อง ให้มีตัวจัดสรรกลางที่จองแบบอะตอมมิก กล่าวคือ เมื่อสองงานขอกล่องเดียวกันพร้อมกัน ต้องมีเพียงงานเดียวที่จองสำเร็จ อย่าให้แต่ละเครื่องอ่านรายการ “ว่าง” แล้วเลือกกล่องเองโดยไม่มีขั้นตอนยืนยันสิทธิ์ร่วมกัน

ในฝั่งตัวรันทดสอบ ควรเก็บความสัมพันธ์ต่อไปนี้ไว้ด้วยกัน:

- ตัวระบุรอบทดสอบและส่วนแบ่งงาน หรือ shard
- ตัวระบุกระบวนการทดสอบและกรณีทดสอบ
- ครั้งที่ลองใหม่
- รหัสกล่องจดหมายและบัญชีทดสอบ
- เจ้าของการจอง เวลาเริ่ม และเวลาหมดอายุการจอง

รายการนี้เป็นข้อมูลของตัวรันทดสอบ ไม่ใช่ฟิลด์ที่ต้องส่งให้ Mailera หมายเลขกระบวนการเพียงอย่างเดียวไม่ควรเป็นตัวระบุเจ้าของ ให้รวมบริบทของรอบและเครื่องที่รันด้วย เพื่อไม่ให้การเริ่มกระบวนการใหม่ถูกมองว่าเป็นงานเดิม

กำหนดอายุการจองเพื่อจัดการงานที่หยุดกลางทาง แต่เมื่อการจองหมดอายุ ให้ตรวจสถานะคำขอเดิมก่อนนำกล่องกลับมาใช้ การหมดสิทธิ์ของเจ้าของเดิมกับการสิ้นสุดคำขอ OTP ควรเป็นคนละสถานะในระบบจัดสรร

หากใช้ที่อยู่อีเมลแฝง ให้ตรวจว่าปลายทางเป็นกล่องแยกจริงหรือไม่ อย่านับจำนวนที่อยู่เป็นจำนวนกล่องที่แยกงานได้โดยอัตโนมัติ [มาตรฐานรูปแบบข้อความอีเมล RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322) แยก envelope ซึ่งมีข้อมูลที่จำเป็นสำหรับการส่งและนำส่ง ออกจากเนื้อหาข้อความ จึงควรตรวจปลายทางที่รับอีเมลจริงก่อนใช้ที่อยู่แฝงแบ่งงาน

![รายการกล่องจดหมายทดสอบใน Mailera พร้อมสถานะการเชื่อมต่อ โดยปิดบังที่อยู่อีเมล](https://mailera.app/media/66c54bacbc6cba73/otp-test-mailbox-list-th-1200.jpg)
_ตรวจกล่องที่เชื่อมต่อใน Mailera แล้วจัดการการจองในตัวรันทดสอบ_

หน้า **กล่องจดหมาย** ใช้ตรวจกล่องที่เชื่อมต่อและสถานะ ส่วนเจ้าของการจองกับคิวงานให้เก็บในตัวรันทดสอบ หากต้องเตรียมการเชื่อมต่อด้วยรหัสผ่านสำหรับแอป ดู[แนวทางใช้ app password กับกล่องจดหมายสำหรับระบบอัตโนมัติ](https://mailera.app/th/blog/email-app-passwords)

## อ่าน OTP ด้วย Mailera ตามลำดับใด?

แยกงานออกเป็นสองส่วนให้ชัด: ตัวรันทดสอบรับผิดชอบการจองและจับคู่คำขอ ส่วน Mailera รับผิดชอบการอ่านกล่องที่ระบุ ดูช่องทางเชื่อมต่อได้ที่[หน้าสำหรับนักพัฒนา](https://mailera.app/th/developers) และรายละเอียดเส้นทางที่ใช้ด้านล่างใน[เอกสาร API](https://mailera.app/th/docs)

ตัวอย่างใช้ `$MAILERA_API_KEY`, `$MAILBOX_ID` และ `$MESSAGE_ID` ที่คุณตั้งจากสภาพแวดล้อมทดสอบของตนเอง คำสั่งอ่านอีเมลอาจแสดงข้อมูลลับในผลลัพธ์ จึงควรรันในเครื่องที่ควบคุมได้ ไม่วางคำสั่งเหล่านี้ลงในขั้นตอน CI ที่พิมพ์ผลตอบกลับทั้งหมดลงบันทึก

### 1. ตรวจรายการกล่อง แล้วจองกล่องพร้อมบัญชีทดสอบ

```bash
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` เป็นเพียงค่าตัวอย่าง ไม่ใช่เวลารอมาตรฐานของทุกระบบ

```bash
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` รวมถึงตัวเลือกโฟลเดอร์ โดยตัวอย่างนี้อ่านจากกล่องขาเข้า:

```bash
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`

```bash
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 โดยอัตโนมัติ](https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets) แยกปัญหาการยืนยันตัวตนกับ API ออกจากปัญหาอีเมลยังไม่มาถึง เพื่อไม่ให้ตัวรันทดสอบรอผิดสาเหตุ

## ข้อผิดพลาดที่พบบ่อยมีอะไรบ้าง?

| อาการ | จุดที่ควรตรวจ | แนวทางแก้ |
| --- | --- | --- |
| รหัสสลับระหว่างงาน | หลายงานใช้กล่องเดียวกัน หรือค้นหาข้ามกล่อง | จองกล่องแบบมีเจ้าของ และระบุรหัสกล่องในเส้นทางอ่าน |
| ได้รหัสจากรอบก่อน | คำขอเดิมยังค้าง หรือคืนกล่องเร็วเกินไป | เริ่มบริบทใหม่ ตรวจคำขอเดิม และพักกล่องเมื่อยังแยกไม่ได้ |
| งานรอไม่จบ | ไม่มีเวลารอสูงสุด หรือสับสนระหว่าง API ล้มเหลวกับไม่พบข้อความ | แยกผลลัพธ์แต่ละแบบและกำหนดจุดหยุด |
| กล่องถูกจองค้าง | กระบวนการหยุดก่อนคืนกล่อง | ใช้เจ้าของและอายุการจอง พร้อมตรวจคำขอค้างก่อนคืนสู่คิว |
| คำขอ API มากเกินไป | แต่ละงานคุมความถี่แยกกัน แต่ใช้คีย์ร่วมกัน | คุมงบคำขอรวมและกระจายจังหวะตรวจ |
| เกิดปัญหาเฉพาะตอนรันหลายเครื่อง | ตัวระบุเจ้าของซ้ำ หรือการจองไม่เป็นอะตอมมิก | ใช้ตัวจัดสรรกลางและผูกเจ้าของกับรอบกับเครื่องที่รัน |

อย่าใช้ผู้ส่งเป็นตัวแยกงานเพียงอย่างเดียว และอย่าถือว่าข้อความที่ยังไม่อ่านเป็นข้อความของงานปัจจุบัน สถานะอ่านแล้วไม่ได้อธิบายความสัมพันธ์ระหว่างอีเมลกับคำขอ OTP

เช่นเดียวกัน อย่าใช้การทำเครื่องหมายว่าอ่านแล้วหรือการย้ายข้อความแทนการล็อกกล่อง ให้ระบบจองเป็นผู้ตัดสินสิทธิ์ใช้งาน ส่วนสถานะข้อความใช้จัดการอีเมลเท่านั้น

บันทึกที่เหมาะกับการหาสาเหตุควรมีตัวระบุรอบ กรณีทดสอบ ครั้งที่ลองใหม่ รหัสกล่อง เวลา และผลลัพธ์ หากต้องอ้างอิงข้อความ ให้เก็บรหัสข้อความแทนเนื้อหาเต็มฉบับ ไม่บันทึก OTP ลงใน log หรือชื่อไฟล์แนบของรายงานทดสอบ

## ต้องปกป้องข้อมูลใด และ Mailera รับผิดชอบส่วนไหน?

ใช้เฉพาะกล่องจดหมายทดสอบที่คุณหรือทีมมีสิทธิ์เข้าถึง แยกจากกล่องส่วนตัวและข้อมูลผู้ใช้จริง ปิดบังที่อยู่อีเมล รหัส OTP และคีย์ในภาพหน้าจอ รวมถึงผลตอบกลับ API ที่อาจติดไปกับรายงานทดสอบ

ใน **การตั้งค่า** เลือก **สร้าง API key** แล้วจำกัด **ขอบเขตกล่องจดหมาย** ให้เป็นกลุ่มทดสอบ ให้คีย์มีเฉพาะสิทธิ์ `read` สำหรับงานอ่านรหัส ไม่เพิ่ม `send` หรือ `manage` เพียงเพื่อให้ชุดทดสอบอ่าน OTP ได้ ดู[ข้อมูลความปลอดภัยของ Mailera](https://mailera.app/th/security) ประกอบการกำหนดสิทธิ์ของทีม

![การสร้างคีย์ API สำหรับอ่านกล่องจดหมายเฉพาะกลุ่มทดสอบ](https://mailera.app/media/bf499900062bf167/ket-noi-yahoo-va-icloud-voi-claude-qua-mcp-read-only-key-vi-1200.jpg)
_ให้คีย์อ่านได้เฉพาะกล่องที่ชุดทดสอบต้องใช้_

สำหรับ GitHub Actions ให้เก็บคีย์ใน secrets เท่านั้นและไม่พิมพ์ค่าลงบันทึก การไม่บันทึก OTP ตั้งแต่ต้นยังควรเป็นกติกาหลัก

Mailera ไม่รับประกันว่าอีเมลจะอยู่ในกล่องขาเข้า จึงควรแยกผลทดสอบแอปออกจากผลตรวจการรับอีเมล และกำหนดเวลารอในตัวรันทดสอบเอง ไม่ผูกความสำเร็จของงานไว้กับเวลาส่งถึงตายตัว

ส่วนการจองกล่อง การจัดคิว และการผูกรหัสกับธุรกรรม ให้ออกแบบในตัวรันทดสอบและแอป เส้นทางอ่าน OTP ใช้ดึงรหัสจากกล่องที่คุณระบุ ไม่ควรใช้แทนระบบควบคุมเจ้าของคำขอ

**ทำสิ่งนี้ด้วย API** — ทุกการดำเนินการในบทความนี้ทำได้ผ่าน REST API พร้อมตัวอย่าง curl, API key และ webhook [ดูเอกสาร API](https://mailera.app/th/docs)
