Ehsan Rasta
Ehsan Rasta
خواندن ۹ دقیقه·۲ ماه پیش

عصر پنجشنبه: تشخیص ایمیل های موقت با Go

عصر پنجشنبه داشتیم شرکت فیفا بازی میکردیم با بچه ها و حسابی سرگرم بودیم که سر و کله یه الرت جدید توی sentry پیدا شد و دیدیم ای بابا ظاهرن یکی از بخش های ثبت نام کاربرها با ایمیل به مشکل خورده.
دسته را دادم به نفر بعد و رفتم سر سیستم دیدم سرویسی که استفاده می کردیم تا معتبر بودن ایمیل وارد شده رو بررسی بکنه به دلایلی ریسپانس درست نمیده. دستی چند تا ریکوست با ایمیل های رندوم زدم بهش و بله دقیقا مشکل از همین جا بود و ظاهرن محدودیت جدیدی گذاشته بودند روی سرویسشون. پس دست به کار شدم و تقریبا شب شده بود که سرویس جدید بالا داشت مثه بنز کار میکرد!


Detecting Disposable Email Addresses Using Go
Detecting Disposable Email Addresses Using Go


اول یکم صورت مساله رو باز کنم و بعد بریم سراغ ادامه عصر پنج شنبه

آدرس ایمیل موقت چیه و به چه دردی میخوره؟

اسمش روش هست دیگه آدرس موقت! یک سری سرویس هستن که به شما یک آدرس ایمیل موقت میدن و شما میتونین از اون ها برای دریافت و یا بعضن برای ارسال ایمیل استفاده کنین و کاربردشون هم جاهایی هست که نمیخاین ایمیل اصلی خودتون رو وارد کنین و مطمئن نیستین اگر آدرس ایمیل اصلی خودتون رو وارد کنین بعدن انقدر ایمیل مارکتینگی و اسپم دریافت نکنین که اینباکستون بترکه ( که البته اون هم راه های بهتری هست براش) یا به هر حال نگران حریم خصوصی هستین و یا اصن اون جایی که میخاین ثبت نام کنین رو قابل نمیدونین که آدرس ایمیل قشنگتون رو داشته باشه :دی

سرچ بزنین از این سرویسا تعداد زیادی وجود داره که چند تاشون رو این پایین میزارم برای کسایی که نمیدونن چی هستن (وقتی داشتم این تیکه رو مینوشتم به تناقض خوردم که اصن این متن اگر باعث بشه آدم های بیشتری با این سرویس ها آشنا بشن نقض قرض شده! علی ایحال کاری که شده).

https://temp-mail.org/
https://www.disposablemail.com/
https://adguard.com/en/adguard-temp-mail/overview.html
...

خب حالا مشکل چیه؟

کاربر خوشحاله که یه آدرس ایمیل الکی وارد کرده توی فرم ثبت نام و الان میتونه از خدمات سایت استفاده بکنه اما مشکل اون جایی پیش میاد که صاحب کسب و کار اطلاعات معتبری از صاحب حساب نداره و اگر مشکلی خدای نکرده پیش بیاد دستش به جایی بند نیست و یا وقتی بخاد (مطابق با قوانینی که قبلن موقع ثبت نام کاربر پذیرفته) به کاربر ایمیلی ارسال بکنه و این ایمیل میتونه خبرنامه باشه و یا ترنزکشنال باشه و مثلن اطلاع رسانی باشه که یکی کاربر رو فالو کرده و یا سناریو های دیگه به مشکل میخوره و بعد مدتی وقتی تعداد ایمیل هایی که میفرسته به این آدرس های نامعتبر زیاد بشه سرویس دهنده ایمیل شاکی میشه و صداش در میاد که آقا این آدرس هایی که وجود ندارن چیه میدی به ما.

تا الان چی کار میکردیم؟

این بخش از سرویس رو خیلی قدیمتر زده بودیم و با استفاده از API یک سرویس تشخیص ایمیل های موقت استعلام اون آدرس رو میگرفتیم و اگر توی خروجی بر میگردوند که این یک آدرس موقته ما هم به کاربر اعلام میکردیم که با این آدرس نمیتونی از خدمات این سایت استفاده کنی.

بخش جذاب کار:

من معمولن قبل این که هر کاری رو بخام شروع کنم مفصلن سلوشن های فعلی و راه هایی که بقیه قبلن رفتن رو بررسی میکنم و بعد خودم دست به کار میشم و این بار هم یه بررسی کردم و دیدم سرویس های دیگه ای هم هستن برای این موضوع ولی مشکل این بود که همه این سرویس ها معمولن با توجه به تعداد درخواست ما کمی هزینه بر بودن و ثانیا مجدد ریسک این موضوع بود که دسترسی بهشون در طولانی مدت از این داخل یا خارج محدود بشه و همچنین کمی ریسپانس تایمشون هم از داخل بالا بود و باعث میشد API ثبت نام دچار کندی یا اختلال بشه و در موقعی هم انقدر اختلال بعضا زیاد میشد که سرویس ثبت نام مجبور میشد بیخیال استعلام بشه و کاربر رو زیرسیبیلی رد بکنه.

در ادامه سرچ ها داخل گیت هاب و کمی گفت و گو با chatGPT تعداد زیادی ریپوزیتاری پیدا کردم که آدرس دامنه های این سرویس های ایمیل موقت رو لیست کرده بودن و معمولن به دو صورت آپدیت میشدن یکی با کمک کاربر هایی که این دامنه ها رو گزارش میکنن و بعضی هم به صورت خودکار و با پایش سرویس های ایمیل موقت آدرس های اون ها رو پیدا و ثبت میکنن. اینجای کار جرقه خورد توی ذهنم و دستی یه لیست از آدرس های موقت از همه این سرویس ها در اوردم و با این ریپازیتوری ها تطبیق دادم و دیدم حدود ۹۰ درصد دقت دارن و لیستشون به نسبت به روز هست پس دست به کار شدم و ایده اولیه این شد که یک سیستمی بنویسم که بیاد و این لیست ها رو از ریپو های گیت هاب این پروژه ها بگیره و همشون رو با هم merge بکنه و یک لیست نهایی بده از دامین هایی که در این سرویس های ایمیل موقت استفاده میشن و بعدش هم یک API بده تا بتونیم این API رو از سمت اپلیکیشن صدا بزنیم و استعلام آدرس رو بگیریم. به چند دلیل از golang استفاده کردم برای این کار اولن چون سریع هست و سرویس نهایی باید حداکثر زیر ۱۰۰ میلی ثانیه ریسپانس بده و همچنین چون یک سرویس نسبتن کوچیک و کم اهمیت هستش (به نسبت سایر اجزا) باید تا حد امکان کم مصرف باشه و دلایل دیگه پس با توجه به اینکه من php , go , node بلدم فقط، php سرعت لازم رو نداره و همچنین مصرف منابعش هم زیاده به نسبت و node سرعتش خوبه و مصرف منابعش هم کمه ولی مشکل اینکه که وقتی داکرایز میشه ایمیج هاش نسبتا حجیم هستن و در آخر چون از go بیشتر خوشم میاد! تصمیم گرفتم با go بزنمش.

تست اولیه:

این تیکه کد فقط برای دست گرمیه و تنها کاری که میکنه لیست هایی که قبلن پیدا کردم رو فراخوانی میکنه و محتوای اون ها رو میگیره و میریزه داخل یک مپ تا بعدن بتونیم ازش استفاده کنیم.

https://gist.github.com/ehsanrasta/e5c7142e31a6daaa07626154e17e1fd4

تا اینجا ما لیست دامنه های موقت رو داریم ولی یه مشکلی هست اگر یکی از این لیست ها بیاد و دامنه gmail.com رو یکی اشتباهی داخلش پوش کنه ما هم دچار مشکل میشیم و کاربرها نمیتونن دیگه با جیمیلشون ثبت نام کنن و این بده پس باید یه لیست سفید هم داشته باشیم که تحت هر شرایطی استعلام این دامنه ها مثبت باشه و دچار خطا نشیم پس بازم دست به سرچ شدم و چند تا وایت لیست خوب هم پیدا کردم و کدی مشابه همین بخش منتهی برای وایت لیست هم نوشتم که دقیقا عملکردش به همین صورت هست. در مرحله بعدی باید همین رو برای تست های بیشتر تبدیلش میکردم به وبسرویس پس نیاز به بود تا روی یک پورت منتظر درخواست بمونه و وقتی کاربر یک ایمیل رو بهش میده بررسی کنه و ببینه توی لیست سفید هست اگر هست بگه اوکی و اگر نیست بره توی لیست سیاه بگرده و اگر اونجا پیداش کرد جواب بده این ایمیل موقته احتمالا. برای اینکار میشه از net/http استفاده کرد ولی بدیش اینه که همه چیز رو آدم باید از اول اختراع کنه و بین Echo و Gin که دو تا از بهترین فریمورک های go هستن من انتخابم برای این پروژه Echo هستش چون سادست و نیازی به امکانات بیشتر Gin نداریم برای این پروژه پس اضافه اش کردم و کدش یه چیزی شبیه این شد:

https://gist.github.com/ehsanrasta/1892a5f547e9b65654be74aec6363d08

کد رو که اجرا کنین اول لیست ها رو بروز میکنه و بعدش هم وبسرویس اجرا میشه و وقتی یه همچنین ریکوستی بزنین در جواب این شکلی وضعیت دامنه رو بر میگردونه:

http://localhost:8080/check?email=princecharles.kristian@afia.pro

ریسپانس سرویس تشخیص ایمیل های موقت
ریسپانس سرویس تشخیص ایمیل های موقت


خب تا اینجا ما mvp پروژه رو آماده کردیم و نشون میده که کار میکنه این ایده منتهی یک سری مشکلات و یک سری بهبود هایی نیاز هست تا بتونیم پروژه رو ببریم روی پروداکشن و به صورت جدی ازش استفاده کنیم.

نهایی سازی پروژه:

خب اول از همه باید یه کران جاب تعریف کنیم تا به صورت خودکار و دوره ای بیاد و همه لیست ها رو بگیره و خودش رو بروز کنه برای این بخش از gocron استفاده میکنیم و فانکشن updateLists رو هر روز ساعت ۱۲ شب صدا میزنیم.

مشکل بعدی اینه که آخرش ممکنه دامنه ای باشه که توی این لیست ها نباشه و هنوز گزارش نشده باشه پس ما هم اشتباهن در خروجی بر میگردونیم که مشکلی نیست برای این مورد یکی از راه هایی که به ذهنم رسید استفاه از همون API های سرویس های دیگه بود که تا الان استفاده میکردیم ولی نکته ای که هست اینکه با بررسی که کردم با تقریب بالای ۹۵ درصد لیست های خودمون کامل هستن ولی بازم برای اطمینان در حالتی که دامنه ای رو نداشته باشیم میتونیم از اون ها استفاده کنیم و خب میگن کار از محکم کاری عیب نمیکنه! پس یه فانکشن هم برای این کار نوشتم که بیاد و ریکوست بزنه بهشون و ازشون استعلام بگیره و اگر جواب مثبت بود اون دامنه رو هم توی لیست های فعلی اضافه کنیم تا دیگه نیاز نباشه بهشون و کش بشه. خروجی نهایی یه چیزی شد شبیه این:

https://gist.github.com/ehsanrasta/daea39b7700c54e0085bb5b4a7e8117e


بریم بالا دیگه!

برای اینکه روی سرور بتونیم کد رو بزاریم و خروجی بگیریم ازش داکرایزش میکنیم و بیلد میگیریم و پوش میکنیم بالا و دیپلوی و تمام. بعدش تنها کاری که داریم اینکه لاگ هاش رو چک کنیم ببینیم داره درست کار میکنه یا نه و اول توی استیج تست هاش رو بگیریم و در نهایت بعد QA بریم برای پروداکشن.

اینم داکرفایل:

https://gist.github.com/ehsanrasta/46f2255866a755bd3c37c5fa1b4f72f0

بعدن چیکارش کنیم؟

اول اینکه این کد هم مثل بقیه کد ها نباید به امان خدا ول بشه و نیاز به نگهداری داره و بررسی های دوره ای و آپدیت کردن نیاز داره و خیلی موضوعات دیگه که از حوصله این متن خارج هست ولی یک سری ایده هم دارم برای اینکه در آینده بهبود داده بشه و دقتش رو افزایش بدیم مثل اینکه بیایم و whois دامنه ها رو بگیریم و چون معمولن عمر این دامنه های ایمیل موقت کوتاهه، برای دامنه هایی با عمر کم بررسی های ثانویه انجام بدیم و بیایم بر اساس فاکتور های دیگه مثل داشتن رکورد SPF و A و معتبر بودن IP میل سروری که بهش وصل هستن امتیاز بدیم به دامنه و اگر از حدی پایین تر بود میتونیم بهش مشکوک باشیم و بریم برای فرآیند Greylisting و بقیه ماجرا رو از اون سمت پیگیری کنیم.


ممنون که وقت گذاشتین و تا اینجا مطالعه کردید اگر سوالی بود جایی از متن و یا به نظرتون راه بهتری وجود داره ممنون میشم از طریق کامنت ها باهام در ارتباط باشید.

goemailapidocker
توسعه دهنده بک اند ویرگول :)
شاید از این پست‌ها خوشتان بیاید