ในบทความนี้ จะแชร์วิธีที่ผมสร้าง subscription sign-up flow พร้อมยืนยันอีเมลที่ไม่ทำให้รำคาญ คุณก็ทำได้เช่นกัน
หากอยากเห็นการทำงานจริง สามารถสมัครรับอีเมลของผมที่ victoria.dev ได้เลย
ตอนนี้ จะแสดงวิธีที่ผมสร้างมัน
แนะนำ Simple Subscribe
หากสนใจจัดการ mailing list หรือ newsletter ของตัวเอง สามารถตั้งค่า Simple Subscribe บน AWS resources ของตัวเองเพื่อเก็บที่อยู่อีเมล
API โค้ดเปิดนี้เขียนด้วย Go และรันบน AWS Lambda ผู้เยี่ยมชมเว็บสามารถสมัครรับรายชื่อ ซึ่งจะเก็บในตาราง DynamoDB พร้อมสำหรับ query หรือ export เมื่อสะดวก
เมื่อใครสมัคร จะได้รับอีเมลขอให้ยืนยันการสมัคร เรียกว่ "double opt-in" แม้ผมชอบเรียกว่า "verified" มากกว่า
Simple Subscribe ทำงานบน infrastructure แบบ serverless และใช้ AWS Lambda จัดการ subscription, confirmation, และ unsubscribe requests
โปรเจกต์ Simple Subscribe พร้อมโค้ดเปิดเผยทั้งหมด อยู่บน GitHub ขอแนะนำให้ดูโค้ดและติดตามไปพร้อมๆ กัน!
ในโพสต์นี้ จะแชร์แต่ละขั้นตอนการสร้าง กระบวนการคิดเบื้องหลัง single-responsibility functions ของ API และข้อพิจารณาด้านความปลอดภัยสำหรับโปรเจกต์ AWS แบบนี้
วิธีสร้าง verified subscription flow
กระบวนการสมัครรับอีเมลแบบไม่ยืนยันตรงไปตรงมา ใครก็ตามใส่อีเมลในกล่องบนเว็บ แล้วอีเมลเข้าฐานข้อมูล
อย่างไรก็ตาม หากผมสอนอะไรเกี่ยวกับการไม่ไว้วางใจ user input ก็ควรจะ疑虑 กระบวนการสมัครแบบไม่ยืนยัน Spam อาจอร่อยตอนทอดในแซนด์วิช แต่ไม่อร่อยตอนมันเพิ่มค่าใช้จ่าย AWS
แม้จะใช้กลยุทธ์อย่าง CAPTCHA หรือปริศนาสำหรับ is-it-a-human verification แต่สิ่งเหล่านี้อาจสร้าง friction พอที่จะทำให้ผู้สมัครทiềm năngกลับไป
แทนที่จะเป็นอย่างนั้น อีเมลยืนยันช่วยรับรองทั้งความถูกต้องของที่อยู่อีเมล และความตั้งใจของผู้ใช้
เพื่อสร้าง subscription flow พร้อมยืนยันอีเมล สร้าง single-responsibility functions ที่ตอบสนองแต่ละขั้นตอนตรรกะ:
- รับที่อยู่อีเมลและบันทึก
- สร้าง token ที่เชื่อมโยงกับอีเมลนั้นและบันทึก
- ส่งอีเมลยืนยันไปที่อีเมลนั้นพร้อม token
- รับคำขอยืนยันที่มีทั้งที่อยู่อีเมลและ token
เพื่อบรรลุเป้าหมายเหล่านี้ Simple Subscribe ใช้ AWS SDK for Go 正式版 เพื่อโต้ตอบกับ DynamoDB และ SES
ในแต่ละขั้นตอน พิจารณาว่าข้อมูล長什麼樣子 และจัดเก็บอย่างไร สิ่งนี้ช่วยจัดการปัญหาเช่น "ถ้าคนพยายามสมัครซ้ำจะเกิดอะไรขึ้น?" หรือแม้แต่ threat modeling อย่าง "ถ้าคนสมัครด้วยอีเมลที่ไม่ใช่ของตนเองจะเป็นไง?"
พร้อมแล้ว? มาแยกแต่ละขั้นตอนดูว่ามีเวทมานิยมอย่างไร
การสมัคร (Subscribing)
กระบวนการสมัครเริ่มจาก web form เหมือนบนหน้าหลักของเว็บผม input พร้อม attributes type="email" required ช่วย validate ด้วย browser เมื่อ submit form ส่ง GET request ไปยัง Simple Subscribe subscription endpoint
Simple Subscribe รับ GET request ที่ endpoint นี้ พร้อม query string ที่มีอีเมลของผู้สมัคร ต่อมาสร้างค่า id และเพิ่ม email และ id ลงตาราง DynamoDB
รายการในตารางตอนนี้长这样:
| confirm | id | timestamp | |
|---|---|---|---|
subscriber@example.com |
false | uuid-xxxxx |
2020-11-01 00:27:39 |
คอลัมน์ confirm ที่เก็บ boolean บ่งบอกว่ารายการนี้เป็นคำขอสมัครที่ยังไม่ได้ยืนยัน เพื่อยืนยันอีเมลในฐานข้อมูล ต้องหา item ที่ถูกต้องและเปลี่ยน confirm เป็น true
ขณะทำงานกับข้อมูล พิจารณาเป้าหมายของแต่ละการจัดการ และว่าอาจเปรียบเทียบ incoming request กับข้อมูลที่มีอยู่อย่างไร
เช่น หากมีคำขอสมัครซ้ำสำหรับอีเมลเดียวกัน จะจัดการอย่างไร?
อาจจะคิดว่า "สร้าง line item ใหม่พร้อม id ใหม่" แต่อาจไม่ใช่กลยุทธ์ที่ดีเมื่อ database ของ serverless app คิดค่าบริการตาม request volume
เนื่องจาก DynamoDB Pricing ขึ้นอยู่กับปริมาณข้อมูลที่อ่าน/เขียน การหลีกเลี่ยงข้อมูลซ้ำซ้อนจึงเป็นประโยชน์
ด้วยความคิดนี้ จะดีกว่าที่จะจัดการคำขอสมัครซ้ำด้วยการ update แทนการเพิ่ม line ใหม่
Simple Subscribe ใช้ function เดียวกันสำหรับเพิ่มหรือ update database item เรียกว่า "update or insert" (upsert)
ใน database อย่าง SQLite ทำได้ด้วย syntax UPSERT ใน DynamoDB ใช้ update operation สำหรับ Go SDK syntax คือ UpdateItem
เมื่อรับคำขอสมัครซ้ำ database item จะ matched บน email เท่านั้น หากพบ line item ที่มีอยู่ id และ timestamp จะถูก override ซึ่ง update record ที่มีอยู่ และหลีกเลี่ยงการ塞滿ตารางด้วยคำขอซ้ำ
วิธียืนยันที่อยู่อีเมล
หลัง submit form ผู้สมัครจะได้รับอีเมลจาก SES มีลิงก์ สร้างจาก email และ id จากตาราง รูปแบบ:
<BASE_URL><VERIFY_PATH>/?email=subscriber@example.com&id=uuid-xxxxx
ใน setup นี้ id เป็น UUID ทำหน้าที่เป็น secret token ให้ identifier ที่ซับซ้อนและเดายาก วิธีนี้ป้องกันไม่ให้คนสมัครด้วยอีเมลที่ไม่ได้ควบคุม
การเข้าเยี่ยมลิงก์ส่ง request ไป verification endpoint พร้อม email และ id ใน query string
ครั้งนี้ สำคัญที่ต้องเปรียบเทียบ email และ id incoming ทั้งคู่กับ database record วิธีนี้ยืนยันว่าผู้รับอีเมลยืนยันคือผู้สร้าง request
Verification endpoint รับรองว่าค่าเหล่านี้ตรงกับ item ใน database แล้วทำ update operation อีกครั้ง ตั้ง confirm เป็น true และ update timestamp item ตอนนี้长这样:
| confirm | id | timestamp | |
|---|---|---|---|
subscriber@example.com |
true | uuid-xxxxx |
2020-11-01 00:37:39 |
วิธี query หาอีเมล
ตอนนี้สามารถ query ตารางเพื่อสร้าง email list ได้ ขึ้นอยู่กับ email sending solution อาจทำ manual, ด้วย Lambda อีกตัว, หรือจาก command line
เนื่องจากข้อมูล requested subscriptions (ที่ confirm เป็น false) เก็บในตารางควบคู่กับ confirmed subscriptions จึงสำคัญที่จะแยกข้อมูลเมื่อ query หาอีเมลส่ง ต้อง ensure ให้ return เฉพาะอีเมลที่ confirm เป็น true เท่านั้น
วิธีให้ลิงก์ยกเลิกสมัคร
เหมือนการยืนยันอีเมล Simple Subscribe ใช้ email และ id เป็น arguments สำหรับ function ที่ลบ item จาก DynamoDB เพื่อ unsubscribe อีเมล
เพื่อให้คนลบตัวเองออกจากรายชื่อได้ ต้องให้ URL ในแต่ละอีเมลที่ส่ง รวม email และ id เป็น query string ไป unsubscribe endpoint จะ长这样:
<BASE_URL><UNSUBSCRIBE_PATH>/?email=subscriber@example.com&id=uuid-xxxxx
เมื่อคลิกลิงก์ query string จะส่งไป unsubscribe endpoint หาก email และ id ที่ให้ตรงกับ database item item นั้นจะถูกลบ
การให้วิธีให้ผู้สมัครลบตัวเองออกจากรายชื่ออัตโนมัติโดยไม่ต้องมีการแทรกแซงจากมนุษย์ เป็นส่วนหนึ่งของปรัชญาจริยธรรมและการเคารพข้อมูลที่ถูกมอบหมายให้
การดูแลข้อมูลของคุณ
เมื่อตัดสินใจรับข้อมูลของคนอื่น มันกลายเป็นความรับผิดชอบของคุณที่จะดูแลมัน ใช้ได้กับทุกอย่างที่สร้าง สำหรับ Simple Subscribe หมายถึง การรักษาความปลอดภัยของ database และการ prune ตารางเป็นระยะ
เพื่อหลีกเลี่ยงการเก็บที่อยู่อีเมลที่ confirm เป็น false เกินช่วงเวลาที่กำหนด ควรตั้งค่า cleaning function ที่รันเป็นตารางเวลา สามารถทำได้ manual, ด้วย AWS Lambda function, หรือ command line
เพื่อทำความสะอาด หา database items ที่ confirm เป็น false และ timestamp เก่ากว่าจุดเวลาที่กำหนด ขึ้นอยู่กับ use case และ request volumes ความถี่ในการ clean up จะแตกต่าง
ขึ้นอยู่กับ use case อาจอยากเก็บ backup ของข้อมูล หากกังวลความสมบูรณ์ของข้อมูล สำรวจ On-Demand Backup หรือ Point-in-Time Recovery สำหรับ DynamoDB
สร้างฐานผู้สมัครรับอิสระของคุณ
การสร้างรายชื่อสมัครรับของตัวเองสามารถเป็นความพยายามที่สร้างพลังได้! ไม่ว่าจะจะเริ่ม newsletter ส่งการแจ้งเตือนเนื้อหาใหม่ หรือสร้างชุมชนรอบงานของคุณ ไม่มีอะไรส่วนตัวและตรงไปตรงมามากกว่าอีเมลจากผมถึงคุณ
ขอแนะนำให้เริ่มสร้างฐานผู้สมัครรับด้วย Simple Subscribe วันนี้ เหมือนงานส่วนใหญ่ของผม มัน open source และฟรีสำหรับการใช้งานส่วนตัว ดำดิ่งสู่โค้ดที่ GitHub repository หรือเรียนรู้เพิ่มที่ SimpleSubscribe.org
หากชอบโพสต์นี้ ผมยินดีที่จะรู้ เข้าร่วมพันๆ คนที่เรียนรู้ไปกับผมที่ victoria.dev เยี่ยมหรือสมัครรับผ่าน RSS สำหรับโปรเจกต์แบบนี้อีก