Skip to content

Email · Giới thiệu bạn bè, báo cáo phụ huynh và lịch thư ​

Một phần của Email. Thư giới thiệu bạn bè, báo cáo phụ huynh, thư sau buổi học, lịch thư, trang lựa chọn nhận thư và thư mời trường.

Ba thư giới thiệu bạn bè (SRC-754) ​

Chỉ đạo chủ dự án 2026-09-16: "Rà soát kỹ tính năng referral… Hệ thống nemo12 cần ghi nhận các hoạt động chính của người được giới thiệu. Và đều gửi các email phù hợp cho cả 2 bên."

Đây là cụm thư duy nhất gửi cho CẢ HAI phía của cùng một sự việc — người rủ và người được rủ. Trước SRC-754 tính năng giới thiệu không gửi lá nào: ai gửi link mời đi thì gửi xong là hết, chuyện tiếp theo xảy ra trong tài khoản của người khác và họ không có cách nào biết. Vòng lặp giới thiệu sống hay chết là ở đây, vì thư là thứ duy nhất tự tìm đến người giới thiệu.

Mã: templatesReferral.ts (khuôn thư) · campaignsReferral.ts (lượt quét) · referral/milestones.ts (định nghĩa mốc + lượt quét mốc).

#Loại (id)Người nhậnKích hoạt (dữ liệu thật trong D1)Khoá chống trùng
1referral-invitedNgười được giới thiệuLượt quét 19:00 VN: vừa được ghi công, trong cửa sổ 30 ngày. Một đời một thưreferred_user_id
2referral-joinedNgười giới thiệuLượt quét 19:00 VN: có mốc joined chưa báo. Gộp mọi người mới trong ngày vào một láreferrer:app:<ngày VN>
3referral-progressNgười giới thiệuLượt quét 19:00 VN: người được giới thiệu đạt mốc mới. Trần riêng 1 thư/7 ngàyreferrer:app:<ngày VN>

Bảy mốc được ghi nhận ​

Yêu cầu "ghi nhận các hoạt động chính của người được giới thiệu" hiện thực bằng bảng referral_milestones (migration 0226). Tiêu chí chọn mốc: đọc được từ dữ liệu ĐÃ CÓ — một mốc đòi thêm chỗ ghi mới ở nơi khác là một mốc sẽ mãi mãi bằng không.

MốcNghĩaĐọc từ
joinedĐã được ghi côngreferral_attributions (ghi ngay lúc claim, không đợi lượt quét)
learner_linkedPhụ huynh thêm con · learner gắn vào hồ sơlearners
diagnostic_doneXong một bài kiểm tra đầu vàoassessment_sessions
first_lessonCó bằng chứng học đầu tiênlearner_evidence
active_weekHọc từ 3 ngày khác nhau trong 7 ngàylearner_evidence
course_enrolledVào một khoá có lịchcourse_enrollments
paidCó quyền học mua bằng tiền (không tính admin cấp tay)curriculum_entitlements

Cùng bảy mốc phục vụ cả hai loại người được giới thiệu, vì chúng hỏi về "những learner thuộc về người này": với phụ huynh là con trong nhà, với học sinh là chính họ.

Mốc còn hiện trên trang giới thiệu (GET /v1/referral/me → people[].milestones), nên người rủ không phải đợi tới lá thư mới biết chuyện gì đang xảy ra.

Ba luật riêng của cụm này ​

#LuậtVì sao
1Thư cho người giới thiệu không phải ô cửa sổ nhìn vào nhà người khác (QG-008). Chỉ có tên hiển thị của chính người được giới thiệu + một câu mốc lấy nguyên từ bảng MILESTONE_WHATGiới thiệu một người bạn không đồng nghĩa với được xem họ học gì. Câu mốc là hằng số viết sẵn — không có đường nào để tên con, môn học hay điểm số của một gia đình lọt sang tài khoản người lạ
2Không hứa tiền chưa có, và cũng không chối bảng giá đang cóHọc phí đã công khai (migration 0177, GET /v1/public/pricing) nhưng cổng thanh toán tự động thì chưa (Q-015), nên quyền lợi ở trạng thái chờ. Thư phải nói đúng thứ đang thiếu là cổng thanh toán. Câu cũ "Nemo12 chưa thu phí" nay sai: phụ huynh vừa xem bảng giá 3.200.000 đ rồi đọc câu đó sẽ hiểu thành một cái cớ để không trả hoa hồng
3Gộp, không bắn từng lá — người rủ được năm người trong một ngày nhận MỘT thư kể năm cái tênNăm lá trong một buổi sáng đọc như máy hỏng, không như tin vui

Vì sao không lá nào gửi ngay trong request ​

referral-invited rất giống thư giao dịch — nó trả lời hành động "bấm link mời rồi đăng nhập" vừa xảy ra. Nhưng thư gửi ngay là thư được miễn trần ngày, và lá này không đáng được miễn: không ai ngồi chờ nó như chờ một cái vé. Mà chịu trần và gửi trong request thì gặp trần là deferred — trong một request không có ai chạy lại, nên "hoãn" ở đó thực chất là "mất hẳn". Đưa vào lượt quét thì deferred mới đúng nghĩa: mai xét lại.

Lý do thứ hai mang tính người đọc: người vừa đăng nhập lần đầu qua link mời đang nhận welcome-parent ngay lúc đó. Bắn thêm một lá thứ hai trong cùng một phút là cách chắc chắn để lá thứ hai bị lướt qua.

Đổi lại, người vừa dùng lời mời vẫn được trả lời ngay tại chỗ: một dòng xác nhận hiện trên màn (ReferralClaimedToast.tsx, gắn ở main.tsx của cả hai app). Câu hỏi "ưu đãi có vào không?" có hạn dùng bằng vài giây; trả lời sau tám tiếng là trả lời một câu đã nguội.

Đánh dấu ĐÃ BÁO sau khi gửi, không phải trước ​

Cột referral_milestones.notified_at là cơ chế gộp: chọn mọi dòng NULL của một người giới thiệu, dựng một lá, gửi, rồi mới đánh dấu. Đánh dấu trước khi biết kết quả là đánh mất vĩnh viễn những mốc nằm trong một lá bị trần ngày hoãn lại — đúng cái bẫy mà dispatchOnce đã tránh cho hàng chống trùng, lặp lại ở một tầng cao hơn. Chỉ sent mới đánh dấu; deferred để nguyên cho ngày mai.

Hai đường chạy ​

NhịpCronLàm gì
02:00 VN0 19 * * *daily-digest, và thứ Hai thêm weekly-report
19:00 VN0 12 * * *Lượt quét thư trạng thái cho bố mẹ: setup-nudge, milestone, inactivity-nudge, exam-countdown, trial-reminder. Rồi lượt riêng cho IELTS Learner (SRC-737, khoá ielts-learner-mail), rồi lượt giới thiệu (SRC-754, khoá referral-mail)

Giờ tối là cố ý: thư nhắc buổi học ngày mai phải tới lúc bố mẹ còn kịp sắp xếp, không phải lúc 2h sáng. Cả hai nhịp chạy dưới withLock và mỗi loại thư có try/catch riêng — một loại hỏng không kéo bốn loại kia theo.

Trần ngày: 3 thư một người (SRC-687) ​

Chỉ đạo chủ dự án 2026-09-07: "tận dụng mọi cơ hội để gửi email cho member, nhưng mỗi người nhận tối đa 3 email mỗi ngày." Hai vế, và vế sau quyết định thiết kế: hệ được phép có mười loại thư và nhiều lý do để gửi, nhưng hộp thư của một gia đình mỗi ngày chỉ mở ba lần — nên thứ đi qua ba khe đó phải là thứ đáng giá nhất.

ĐiềuCách làmVì sao
Đơn vị "ngày"Ngày lịch Việt Nam, không phải 24 giờ trượtHộp thư của phụ huynh sống theo ngày của họ. Đếm trượt thì thư 23:00 hôm qua chặn thư 08:00 hôm nay, và không ai giải thích nổi
Đếm cái gìMọi thư đã gửi trong ngày, kể cả thư giao dịchTrần nói về thứ người ta NHẬN, không nói về thứ hệ thống muốn gửi
Ai bị chặnThư theo lịch (7 loại) + 8 thư IELTS + 3 thư giới thiệu
Ai không bị chặnThư trả lời một hành động vừa xảy ra: welcome-parent, diagnostic-ready, event-confirmationAi vừa bấm "Đăng ký sự kiện" phải nhận được vé, kể cả khi sáng nay đã nhận thư tổng kết. Chặn một cái vé vì đủ hạn mức là làm hỏng việc người ta đang chờ
Bị chặn thì saoTrả về deferred, không giành hàng chống trùngHoãn mà vẫn tiêu suất thì lá thư bị hoãn sẽ không bao giờ đi. deferred khác skipped: một cái là mai xét lại, một cái là thôi hẳn

Muốn biết trần có ăn không mà không phải đợi cron: gọi GET /v1/admin/email-pass-preview. Nó chạy đúng một đường mã với lượt thật (dryRun chảy xuống tận dispatchOnce), chỉ khác chỗ dừng — một bản mô phỏng viết riêng sẽ trôi khỏi bản thật đúng vào lúc người ta tin nó nhất. Kết quả trả về sent_today của từng người nhận, vì "hôm nay đã nhận mấy thư" là con số duy nhất giải thích được một dòng deferred.

Thứ tự ưu tiên khi nhiều thư cùng tranh một khe — xếp theo hạn chót, không theo giá trị cảm tính, vì hạn chót là thứ đo được:

  1. trial-reminder — buổi học ngày mai không dời được
  2. exam-countdown — ba mốc cố định, trượt là mất mốc
  3. milestone — khen muộn vẫn là khen, nhưng khen trong tuần đó mới có nghĩa
  4. inactivity-nudge — chậm một ngày không mất gì
  5. setup-nudge — chậm một ngày không mất gì

Sáng thứ Hai, weekly-report chạy trước daily-digest vì hai lá tranh cùng một khe của cùng một người: bản tổng kết bảy ngày đáng đọc hơn bản một ngày. Nó phải thắng bằng thứ tự có chủ ý, không phải bằng may mắn.

Tổng kết số liệu thư cho chủ dự án (SRC-1288) ​

Chỉ đạo 07.10.2026: email tổng kết ngày và tuần: số email gửi đi, số lượt mở, tỷ lệ mở, top 10 người hay mở, thời điểm mỗi người hay mở, link tới một dashboard về email.

ThưKhi nàoKhoảng số liệu
admin-email-dailyLượt cron 12:00 UTC (19:00 VN), mỗi ngàyCác lá gửi hôm qua (giờ VN); lượt mở tính tới lúc chạy, nên mỗi lá đã có ít nhất 19 giờ để được mở
admin-email-weeklyCùng lượt, chỉ tối thứ Hai (giờ VN)Bảy ngày từ thứ Hai tới Chủ nhật vừa qua

Người nhận: EMAIL_REPORT_TO, để trống thì về EMAIL_COPY_TO. Thư vận hành: miễn trần ngày, một kỳ một lá, gửi cả khi kỳ ấy không có lá nào.

Bảng số liệu: admin.nemo12.com/#emails, khối "Số liệu thư" ở đầu tab (Hôm nay / 7 ngày / 30 ngày), qua GET /v1/admin/email-stats?days=. Thư và màn hình dùng cùng một hàm emailStats (email/stats.ts), nên không lệch con số.

Cách đếm:

  • Tỷ lệ mở = số lá có ít nhất một lượt mở / số lá gửi thành công. Một lá mở ba lần vẫn là một lá.
  • Top 10 người hay mở xếp theo số lá đã mở; hoà thì người nhận ít thư hơn đứng trước.
  • Giờ hay mở của một người là giờ (giờ VN) có nhiều lượt mở nhất của họ trong khoảng.
  • Thư mẫu (sample:*) và bản sao gửi riêng (copy:*) bị loại hẳn.

Ba giới hạn của con số, in ngay trong thư và trên màn hình:

  1. Lượt mở là cận dưới: người tắt tải ảnh thì không để lại dấu; Gmail và Apple Mail tải ảnh qua proxy hoặc tải trước, nên một lượt proxy chưa chắc là một người đã đọc.
  2. Bản sao cc/bcc nằm chung lá với bản gốc, mang cùng ảnh theo dõi. Chủ dự án mở bản sao thì được ghi là người nhận đã mở; khi ấy tỷ lệ thật thấp hơn con số, và top người mở có thể chỉ là lượt mở của chủ dự án. Báo cáo ghi rõ khi chế độ ấy đang bật.
  3. Chế độ EMAIL_COPY_MODE=separate (thêm ngày 07.10.2026) gửi bản sao thành lá riêng với ảnh theo dõi riêng, ghi sổ copy:<loại gốc>, mang đúng người gửi của lá gốc, không tiêu suất trần ngày. Đổi sang chế độ này thì phụ huynh không còn thấy địa chỉ chủ dự án trong CC, tức là đảo lại quyết định dùng CC ngày 07.09.2026, nên mặc định vẫn là cc cho tới khi chủ dự án đổi.

Nút Tham gia, thư cho gia đình chưa học và phụ huynh tự học Marlins (SRC-1336) ​

Chỉ đạo chủ dự án 10.10.2026, bước 5 và 6 của lộ trình thư.

  • Nút Tham gia. Mục Tổng quan của mỗi chương trình trên learn có nút "Tham gia NEMO X" (apps/learn/src/JoinProgram.tsx, POST/GET /v1/me/program-join). Thư THEO LỊCH của chương trình (chuỗi thư IELTS, báo cáo tuần, Learning Plan) chỉ đi tới gia đình đã tham gia; thư xác nhận và thư sau buổi học không bị chặn. Một học sinh tính là đã tham gia khi chính em hoặc một phụ huynh của gia đình em đã bấm. Người đang học trước 11.10.2026 được ghi sẵn (grandfathered, migration 0345, bảng program_joins).
  • family-inactive. Gia đình đã thêm con nhưng chưa có buổi học nào: ba lá vào ngày thứ 3, 10, 24 sau khi tạo tài khoản, mỗi lá một việc làm ngay theo chương trình đã xem. Có buổi học đầu tiên là thôi. Khác inactivity-nudge (con đã học rồi nghỉ).
  • marlins-parent-weekly. Tối Thứ Tư, cho phụ huynh có mở bài khoá học bố mẹ trong 30 ngày qua: các khoá đang học, số bài đã mở, số bài kiểm tra, lần gần nhất, bước tiếp theo. Nghỉ từ 7 ngày thì thư đổi giọng thành lời mời quay lại.
  • Code: email/familyMail.ts, programInterest/joins.ts. Lượt thư mẫu SAMPLE_SEND_ON = 2026-10-11#1.

Thư Có gì mới hằng tuần (SRC-1328) ​

Chỉ đạo chủ dự án 10.10.2026: thư "có gì mới" mỗi tuần, viết riêng cho phụ huynh và cho học sinh, bản nháp gửi chủ dự án trước.

  • Tối Thứ Năm 19:00: BẢN NHÁP cả hai lá về EMAIL_COPY_TO, tiêu đề [NHÁP · gửi DD.MM.YYYY], kèm danh sách tin còn draft để chủ dự án kịp công bố trước Chủ nhật. Tuần chưa có tin đã công bố thì bản nháp nói thẳng là Chủ nhật sẽ không có thư.
  • Tối Chủ nhật 19:00: whats-new-parent cho phụ huynh, whats-new-learner cho học sinh có tài khoản riêng, gửi từ NEMO <support@…>. Chỉ khi WHATS_NEW_ENABLED = 1 và tuần (Thứ Hai tới Chủ nhật, giờ VN) có ít nhất một tin published trong product_updates. Không có tin thì không gửi.
  • Bản phụ huynh nói tin giúp gì cho việc học của con và gợi ý một câu hỏi cụ thể; bản học sinh mời thử ngay. Ngừng nhận được riêng (dòng thư news).
  • Code: email/whatsNew.ts.
  • 10.10.2026 chủ dự án bật gửi thật: MAIL_SERIES_ENABLED, PARENT_REPORTS_ENABLED, PLAN_MAILS_ENABLED, WHATS_NEW_ENABLED đều 1; bản sao về EMAIL_COPY_TO đổi từ CC sang BCC (EMAIL_COPY_MODE = bcc), phụ huynh không còn thấy địa chỉ đối chứng.

Xem trước 3 ngày trước mỗi lượt thư theo lịch (SRC-1326) ​

Chỉ đạo chủ dự án 10.10.2026. Mỗi tối 19:00 (giờ VN) lượt cron xét ngày D+3: loại thư nào có lịch gửi vào thứ của ngày ấy (chuỗi thư IELTS, báo cáo tuần từng chương trình, thư tuần cho chủ dự án) thì bản mẫu của nó đi về EMAIL_COPY_TO, tiêu đề mở bằng [XEM TRƯỚC · gửi DD.MM.YYYY].

  • Bảng thứ gửi: SCHEDULED_WEEKDAY trong email/previewAhead.ts; test bắt nó khớp chữ trong CADENCE.
  • Gửi cả khi công tắc của loại thư đang tắt: xem trước là để duyệt trước khi bật.
  • Thư theo sự kiện (chào mừng, mốc, sau buổi học) không có ngày gửi cố định nên không có bản xem trước; chúng dùng lượt thư mẫu SAMPLE_SEND_ON.
  • Mỗi (ngày gửi, loại thư) một lá, khoá trong email_dispatches (preview-ahead).

Người gửi riêng cho Referral / Affiliate, bỏ no-reply@ (SRC-1319) ​

Chỉ đạo chủ dự án 10.10.2026:

  • Người tham gia chương trình giới thiệu nhận thư từ NEMO Partners <partners@nemo12.com>, đầu thư và chân thư cũng là NEMO Partners (program partner trong email/program.ts). Áp cho hai lá gửi NGƯỜI GIỚI THIỆU: referral-joined, referral-progress; nội dung có thêm lời cảm ơn người đồng hành. referral-invited gửi gia đình ĐƯỢC mời nên vẫn là thư xác nhận chung.
  • Không còn thư nào đi từ no-reply@. Thư chung và thư xác nhận đi từ NEMO <support@nemo12.com> (DIGEST_FROM); support@ và partners@ là hộp thư nhận, thư trả lời chuyển về chủ dự án. Đường lui khi Email Service từ chối địa chỉ sub-brand cũng là support@.
  • Tên thương hiệu trong MỌI chữ của thư (tiêu đề, thân thư, nút) là NEMO, không còn Nemo12; Nemo12 Tutors thành NEMO TUTOR. Địa chỉ web nemo12.com giữ nguyên.
  • NEMO WALK (10.10.2026): thư đi từ và nhận về walk@nemo12.com. Trang nemo12.com/walk và learn.nemo12.com/walk hiện địa chỉ này để liên hệ, và cả hai đều ghi lượt xem vào sổ quan tâm walk.

Báo cáo phụ huynh sau buổi học và báo cáo tuần (SRC-1311) ​

Chỉ đạo 09.10.2026: phụ huynh nhận báo cáo sau mỗi buổi học của NEMO AI, NEMO SPEAK & NEMO WALK, NEMO Grammar, NEMO IELTS, hoặc sau khi học sinh kết thúc một section tự học; báo cáo hằng tuần cho từng phụ huynh, kể cả khi học sinh không học gì; mọi email CC dac2205@gmail.com và BCC dangtuyethong2324@gmail.com. Mã: email/parentReports.ts.

ThưKhi nàoNgười gửi
ielts-session-report, grammar-session-report, speak-session-report, walk-session-report, ai-teen-session-reportCron mỗi giờ: một (học sinh, chương trình, ngày VN) khi hoạt động cuối cùng của ngày đã qua 60 phútĐịa chỉ của chương trình (ielts@, grammar@, speak@, walk@, ai-teen@)
<program>-weekly-report (xem SRC-1313)Tối thứ Hai 19:00 VN, mỗi chương trình một thư, mọi học sinh thuộc chương trình, kể cả tuần không họcĐịa chỉ của chương trình

"Một buổi" đọc từ dữ liệu thật, không ước lượng:

Chương trìnhNguồn
NEMO IELTSlearning_events, bốn kỹ năng: số câu đúng/số câu, số phút; Writing/Speaking nói số bài
NEMO GRAMMARlearning_events skill grammar: số bài làm đúng lần đầu, các chủ đề
NEMO SPEAKspeak_pair_sessions đã kết thúc: chủ đề, bạn cặp, giờ xong
NEMO WALKwalk_checkins: buổi có mặt, bạn cặp
NEMO AI TEENai_teen_exercise_results + ai_teen_step_ticks: bài tập đúng theo lesson, số bước

"Phụ huynh" là chủ gia đình hoặc người giám hộ (parentsOfLearner). Learner tự đăng ký có gia đình do chính họ làm chủ, nên thư tới chính họ.

Thư tuần mới thay weekly-report khi công tắc bật: lá cũ chỉ đi khi con có học, nên phụ huynh của học sinh không đăng nhập chưa từng nhận gì. Cả hai không bao giờ cùng chạy.

BCC cố định EMAIL_BCC_TO gắn ở kênh gửi, nên phủ MỌI lá thư (cả thư outreach từ hello@), cộng với bản CC EMAIL_COPY_TO. Trang minh bạch dữ liệu khai bên nhận BCC này cho phụ huynh, vì đó là chỗ duy nhất họ biết nó tồn tại.

Công tắc PARENT_REPORTS_ENABLED = "0": thư sau buổi chạy khô, thư tuần cũ giữ nguyên. Lượt gửi thử (PARENT_REPORT_TEST_ON = một ngày VN): chạy MỘT lần trong ngày ấy ở cron mỗi giờ, mỗi chương trình 3 học sinh có hoạt động gần nhất trong 90 ngày, dựng thư sau buổi + thư tuần bằng dữ liệu thật, gửi CHỈ về EMAIL_COPY_TO (và bản BCC), tiêu đề [THỬ → <phụ huynh đáng lẽ nhận>].

Chưa quyết, chờ chủ dự án: thư tổng kết hằng ngày (daily-digest, ielts-daily-digest) trùng một phần với thư sau buổi IELTS. Bật thư sau buổi mà không tắt thư tổng kết thì phụ huynh của học sinh IELTS nhận hai lá về cùng một ngày học.

Thư cho ai, chân thư, thư tuần từng chương trình (SRC-1313) ​

Chỉ đạo 10.10.2026, sửa lên mục SRC-1311 ở trên:

Thư dành cho ai, nói ngay từ đầu. Bảng AUDIENCE (email/audience.ts) khai mọi loại thư là parent, learner hay other (thư vận hành). Kênh gửi đọc bảng ấy để:

ChỗThư cho phụ huynhThư cho học sinh
Đầu tiêu đề thư (trước cả [MẪU], [THỬ])[Phụ huynh][Học sinh]
Ngay trên tiêu đề trong thân thư"THƯ DÀNH CHO PHỤ HUYNH""THƯ DÀNH CHO HỌC SINH"
Dòng đầu bản chữ trơnnhư trênnhư trên

Một lá có thể đổi đối tượng lúc gửi (Email.audience). Thư báo cáo "phụ huynh" của một learner tự đăng ký đi tới chính learner (họ là chủ gia đình của chính mình; parentsOfLearner trả cờ self), nên thư ấy là bản cho học sinh: "Chào Dam Tu, bạn vừa xong...". Trước đây nó thành "Dam Tu thân mến, Dam Tu vừa xong...". Cổng subjectNames.test.ts bắt mọi bản mẫu phải có trong bảng.

Chân thư MỌI thư không có chữ nemo12.com: chỉ tên NEMO (thư chung) hoặc tên sub-brand, "Thư tự động, vui lòng không trả lời thư này", "© 2026 NEMO", "Ngừng nhận thư từ NEMO". Đường dẫn vẫn trỏ về trang thật. Địa chỉ người gửi vẫn mang tên miền: thư không gửi được nếu thiếu nó.

NEMO AI gửi từ NEMO AI <ai@nemo12.com> (không có nemo-ai@); ai-teen@ cũ còn là hộp thư nhận phụ. Tên khoá trong thư: ai-teen-3 → "NEMO AI 3".

Thân thư chia khối: đoạn cách đoạn rộng hơn ở khung chung (p, dim), và đề mục khối (section) cho thư báo cáo: lời chào, một câu tóm tắt, "Hôm nay con đã làm", "Gợi ý cho phụ huynh".

Không còn thư tuần gộp nhiều môn. Mỗi chương trình một thư tuần riêng (ielts-, grammar-, speak-, walk-, ai-teen-weekly-report), gửi từ địa chỉ của chương trình, tối thứ Hai, cho mọi học sinh THUỘC chương trình (từng có hoạt động ở đó, hoặc có dòng quan tâm), kể cả tuần không học. parent-weekly bỏ; weekly-report cũ vẫn nhường chỗ khi PARENT_REPORTS_ENABLED = "1".

Lượt gửi thử nhận dạng 2026-10-10#2: phần ngày dùng để so, cả chuỗi là khoá một-lần, nên gửi lại trong cùng ngày chỉ cần tăng số.

Trang lựa chọn nhận thư và huỷ đăng ký một chạm (SRC-1317) ​

Chỉ đạo chủ dự án 10.10.2026: link cuối thư không được dẫn thẳng tới API. Nó mở trang nemo12.com/email/preferences/<token>, nơi người nhận thấy hai cụm: những gì họ đang nhận kèm lợi ích, và những gì sẽ bỏ lỡ nếu ngừng. Có đúng MỘT nút nhỏ để ngừng, và ba chỗ để giữ nguyên như cũ.

  • Đơn vị ngừng là một dòng thư của một chương trình (email/streams.ts): báo cáo sau buổi, báo cáo tuần, tổng kết ngày, mốc tiến bộ, thư nhắc, chuỗi thư. Ngừng báo cáo sau buổi NEMO GRAMMAR không làm câm báo cáo tuần hay thư của chương trình khác. Ghi vào email_suppressions (scope email, khoá <địa chỉ>#<chương trình>:<dòng>), nên trang admin danh sách không gửi thấy luôn; isSuppressed đọc bảng này ở chốt chung của mọi thư.
  • Thư xác nhận và tài khoản là dòng bắt buộc: trang hiện chúng nhưng không có nút ngừng.
  • Một trang cho mọi lần quyết định của cùng một người: token chỉ ra lá thư vừa bấm, API (GET/POST /email/preferences/{token}) trả dòng thư tương ứng. Bấm ngừng là xong, không hỏi lại.
  • Link cũ /e/u/<token> trong thư đã gửi chuyển sang trang mới (GET không ghi gì, vì máy quét link mở mọi đường dẫn).
  • Học theo luật người gửi hàng loạt của Gmail và Yahoo (02.2024, RFC 8058), rút ra khi rà soát skill email-best-practices của resend/resend-skills: mọi thư ngừng được mang header List-Unsubscribe + List-Unsubscribe-Post: List-Unsubscribe=One-Click, trỏ tới POST /e/one-click/{token}, làm việc ngay không cần trang xác nhận. Thư giao dịch, thư mẫu và bản sao không mang header này.

Thư sau buổi học chi tiết, và thư riêng cho học sinh (SRC-1316) ​

Chỉ đạo chủ dự án 10.10.2026: thư gửi phụ huynh sau mỗi buổi phải trả lời được hôm nay con luyện kỹ năng nhỏ nào, bao lâu, điều gì phụ huynh nên biết, điểm mạnh, chỗ cần cải thiện, và nên trò chuyện với con điều gì. Học sinh nhận một thư riêng, không phải bản sao thư của bố mẹ.

  • Thư phụ huynh gồm các cụm: Thời gian học · Các kỹ năng nhỏ con đã luyện · Điểm mạnh trong buổi · Cần tập trung cải thiện · Điều phụ huynh nên biết · Nội dung nên trao đổi cùng con + 3 câu hỏi gợi ý, rồi một đoạn viết tự do, ấm áp.
  • Kỹ năng nhỏ đọc từ dữ liệu thật: IELTS lấy tên, mô tả và bẫy thường gặp trong ielts_micro_skills; Grammar theo chủ đề; SPEAK, WALK, NEMO AI theo bài đã làm. Không bịa nhận xét.
  • Điểm mạnh là kỹ năng đúng từ 80%, cần cải thiện là dưới 60%, chỉ khi có ít nhất 3 câu; ít hơn thì thư nói thẳng là chưa đủ dữ liệu để nhận xét.
  • Thư học sinh (audience learner) nói với chính con, cùng nội dung nhưng câu hỏi là "Tự hỏi mình 3 câu".
  • Luôn đủ 3 câu hỏi, kể cả buổi ít dữ liệu; bản học sinh viết lại câu hỏi thành giọng "bạn".
  • Chân mọi thư: "Có câu hỏi? Bạn cứ trả lời thư này", vì mọi địa chỉ gửi nay đều nhận thư.
  • Lượt gửi thử PARENT_REPORT_TEST_ON = 2026-10-10#4 gửi bản đã sửa về hộp thư chủ dự án.

Lịch thư và hồ sơ thư từng người (SRC-1314) ​

Chỉ đạo 09-10.10.2026: một chỗ đánh dấu tần suất và lịch gửi email, bấm vào xem nội dung chính, from và subject của từng dạng email; bấm vào mỗi cá nhân thì xem được họ đang nhận những email nào, đã nhận những email nào, bao nhiêu, open rate thế nào.

admin.nemo12.com/#emails, khối Lịch thư ở đầu tab (email/catalog.ts):

CộtNguồn
Chương trình, người gửiprogramOf + fromFor, cùng hàm với kênh gửi
Cho aibảng AUDIENCE (phụ huynh / học sinh / vận hành)
Tiêu đềbản mẫu, đã gắn nhãn đối tượng như lá thật
Lịch gửiCADENCE (khai cho từng loại thư; cổng test bắt loại thư quên khai)
Trạng thái"đang gửi" hoặc "chạy khô" theo công tắc của loại thư (MAIL_SERIES_ENABLED, PARENT_REPORTS_ENABLED)
7 ngàysố lá đã gửi và tỷ lệ mở

Bấm một dòng: bản xem trước dựng bằng finalizeEmail của tracking.ts, đúng hàm dùng khi gửi thật, hiện trong iframe sandbox. Ô Tra một người (hoặc bấm người nhận trong bảng "Thư gần đây") mở hồ sơ: đang nhận gì (danh sách chặn, chương trình quan tâm, các con và chuỗi thư), các loại thư đã nhận, 50 lá gần nhất, tỷ lệ mở. Endpoint: GET /v1/admin/email-catalog, GET /v1/admin/email-catalog/{id}/preview, GET /v1/admin/email-person?email=.

Thư mời trường tháng 10.2026 từ hello@nemo12.com (SRC-1110) ​

Không phải thư gửi phụ huynh: đây là thư mời một TRƯỜNG tham gia ưu đãi 100 suất NEMO IELTS + 100 suất NEMO SAT. Đi từ Nemo12 <hello@nemo12.com>, trả lời về hello@, bản đối chứng luôn CC (nhìn thấy được) tới EMAIL_COPY_TO = dac2205@gmail.com (SRC-1116, 28.09.2026; trước đó là BCC). CC nghĩa là trường nhận thư thấy địa chỉ của chủ dự án và "Trả lời tất cả" vào đó; chủ dự án đã chấp nhận. Khuôn thư vi/en/id/th là dữ liệu trong bảng outreach_templates, có dòng "reply 'unsubscribe'" do mã gắn. Chỉ gửi dòng đã duyệt, 1 thư + 1 nhắc mỗi trường, tối đa 50 thư/ngày, công tắc OUTREACH_SEND_ENABLED. Không đi qua sendTrackedEmail: không ảnh theo dõi lượt mở, không tính vào trần 3 thư/người/ngày của phụ huynh. Thiết kế đầy đủ và việc chủ dự án phải làm để hello@nemo12.com nhận được thư trả lời: SDD-049 §4-5.