أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

أتمتة فرز Gmail بـ Claude Haiku و Gmail API — من 40 دقيقة لـ 30 ثانية يوميًا

📅 ٢٠ أبريل ٢٠٢٦⏱ 6 دقائق قراءة
أتمتة فرز Gmail بـ Claude Haiku و Gmail API — من 40 دقيقة لـ 30 ثانية يوميًا

أتمتة فرز Gmail بـ Claude Haiku و Gmail API — من 40 دقيقة لـ 30 ثانية يوميًا

لو inbox بتاعك بياكل منك 40 دقيقة صبح كل يوم في تصنيف إيميلات يدويًا، السكربت اللي تحت بياخد المهمة دي في أقل من 30 ثانية. بيسحب الإيميلات غير المقروءة من Gmail، يبعت العنوان والـ snippet لـ Claude Haiku 4.5، ويرجع يحطّ labels زي "Urgent" و "Clients" و "Newsletters". التكلفة الفعلية لحجم 100 إيميل يوميًا حوالي 1.28 دولار شهريًا، والدقة على العينات اللي اختبرتها فوق 93%.

شاشة هاتف تعرض تطبيق Gmail مع عدد كبير من الإيميلات غير المقروءة — سياق أتمتة فرز الـ inbox

المشكلة باختصار

الفلاتر الأصلية في Gmail شغّالة بـ rules ثابتة: "لو الـ sender بكذا، ضيف label كذا". المشكلة إن الـ rules دي بتفشل على إيميلات جديدة من senders لسه مش متعرّف عليهم، أو على رسائل نفس الـ sender بس بنيّة مختلفة (مرة فاتورة، مرة إعلان، مرة سؤال حقيقي). النتيجة: كل صبح بتبص في 80-120 إيميل غير مقروء وبتقرّر يدويًا لكل واحد فيهم.

ركز: المهمة دي بطبيعتها classification task — قرار واحد من قائمة محددة. وده بالظبط اللي LLM رخيص زي Haiku 4.5 بيعمله ببراعة وبفلوس قليلة.

الفكرة بتمثيل بسيط

تخيّل موظف استقبال في عيادة. كل مريض داخل بيقول اسمه وشكواه في سطرين. قدام الموظف ورقة فيها 5 فئات: طوارئ، كشف عادي، متابعة، استفسار، إعلانات مندوبين. الموظف بيقرأ الشكوى، يبصّ على الورقة، ويقرّر. هو مش بيعالج، مش بيكتب روشتة — بيصنّف وخلاص.

أتمتة فرز Gmail شغّالة بنفس المنطق بالظبط. المريض = الإيميل. الورقة = قائمة الفئات في الـ prompt. القرار = إضافة label. ومفيش داعي لموديل كبير ومكلف — موديل صغير كفاية لأنه بيرد بكلمة واحدة من قائمة معلومة.

المفهوم بشكل دقيق — LLM classifier

LLM classifier هو استدعاء language model مع تعليمات صارمة بترجّع output في نطاق محدود (enum). بدل ما الموديل يرد بنص مفتوح، انت بتقيّده بـ system prompt صريح: "رد بكلمة واحدة بس من القائمة دي". النتيجة deterministic تقريبًا، والـ output tokens قليلة جدًا (5-10 tokens لكل استدعاء)، وده اللي بيخلّي التكلفة الشهرية في حدود دولار.

الافتراض هنا: إن الفئات أقل من 15، وكل فئة ليها وصف واضح يفرّقها عن الباقي. لو الفئات متداخلة أو عددها فوق 20، الدقة بتنهار وساعتها تحتاج تروح لـ fine-tuning أو embeddings بدل prompting مباشر.

المتطلبات والإعداد

  1. حساب Google Cloud (مجاني) مع تفعيل Gmail API من Console.
  2. OAuth 2.0 credentials نوع Desktop app، تحمّلها كملف credentials.json.
  3. مفتاح Anthropic API من platform.claude.com، تحطّه في environment variable اسمه ANTHROPIC_API_KEY.
  4. Python 3.10+ مع المكتبات:
Bash
pip install google-api-python-client google-auth-oauthlib anthropic
شاشة محرّر أكواد يعرض سكربت Python قيد الكتابة — تمثيل لسكربت التصنيف الذي يستدعي Claude API و Gmail API

السكربت الكامل

Python
import os
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from anthropic import Anthropic

SCOPES = ["https://www.googleapis.com/auth/gmail.modify"]

LABELS = {
    "Urgent": "إيميل عميل حالي يطلب رد عاجل أو يذكر مشكلة إنتاج أو عطل.",
    "Clients": "تواصل عمل من عميل أو شريك، ليس عاجلًا.",
    "Newsletters": "نشرات بريدية أو محتوى تسويقي أو إعلانات.",
    "Receipts": "فواتير، إيصالات، تأكيد مدفوعات، اشتراكات.",
    "Other": "أي شيء خارج الفئات السابقة."
}

def gmail_service():
    creds = None
    if os.path.exists("token.json"):
        creds = Credentials.from_authorized_user_file("token.json", SCOPES)
    if not creds or not creds.valid:
        flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES)
        creds = flow.run_local_server(port=0)
        open("token.json", "w").write(creds.to_json())
    return build("gmail", "v1", credentials=creds)

def classify(anth, subject, snippet):
    labels_desc = "\n".join([f"- {k}: {v}" for k, v in LABELS.items()])
    msg = anth.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=10,
        system=(
            "صنّف الإيميل في واحدة من الفئات دي فقط:\n"
            f"{labels_desc}\n"
            "رد بكلمة واحدة: اسم الفئة بالظبط، بدون شرح."
        ),
        messages=[{"role": "user", "content": f"العنوان: {subject}\nالملخص: {snippet}"}],
    )
    return msg.content[0].text.strip()

def get_or_create_label(svc, name):
    existing = svc.users().labels().list(userId="me").execute().get("labels", [])
    for lbl in existing:
        if lbl["name"] == name:
            return lbl["id"]
    new = svc.users().labels().create(userId="me", body={"name": name}).execute()
    return new["id"]

def run():
    svc = gmail_service()
    anth = Anthropic()
    label_ids = {name: get_or_create_label(svc, name) for name in LABELS}
    unread = svc.users().messages().list(
        userId="me", q="is:unread newer_than:1d", maxResults=100
    ).execute()
    for m in unread.get("messages", []):
        msg = svc.users().messages().get(
            userId="me", id=m["id"], format="metadata", metadataHeaders=["Subject"]
        ).execute()
        subject = next(
            (h["value"] for h in msg["payload"]["headers"] if h["name"] == "Subject"),
            "",
        )
        snippet = msg.get("snippet", "")[:400]
        category = classify(anth, subject, snippet)
        if category in label_ids:
            svc.users().messages().modify(
                userId="me", id=m["id"], body={"addLabelIds": [label_ids[category]]}
            ).execute()
            print(f"[{category}] {subject[:60]}")

if __name__ == "__main__":
    run()

جدولة السكربت يوميًا

Bash
# crontab -e — تشغيل يومي الساعة 8 صباحًا
0 8 * * * /usr/bin/python3 /home/user/gmail_sort.py >> /var/log/gmail_sort.log 2>&1

للسيرفرات الجادة، systemd timer أفضل من cron لأنه بيدّيك logs أنضف عبر journalctl ويتعامل أحسن مع الفشل. على macOS استخدم launchd، وعلى ويندوز Task Scheduler بنفس المنطق.

الحسبة الفعلية — التكلفة والحدود

  • التوكنز: 100 إيميل × ~400 توكن دخل = 40K دخل يوميًا. الرد 5 توكن × 100 = 500 توكن خرج.
  • شهريًا: 1.2M دخل + 15K خرج = 1.2 × $1 + 0.015 × $5 = $1.28/شهر تقريبًا.
  • مع prompt caching لـ system prompt الثابت، التكلفة ممكن تنزل تحت $0.50/شهر.
  • حدود Gmail API: 250 quota unit/user/second و 1 مليار unit/day. استدعاء messages.modify = 5 units، يعني تقدر تعدّل 50 رسالة/ثانية لنفس المستخدم بدون ما تضرب الـ limit.

الأرقام دي مبنية على سعر Haiku 4.5 الرسمي ($1/M دخل، $5/M خرج) وحدود Gmail API الرسمية — المصادر في آخر المقال.

trade-offs صريحة

بتكسب: 35-40 دقيقة يوميًا، تركيز أعلى صباحًا، تصنيف ثابت بغضّ النظر عن مزاجك.

بتخسر: تكلفة شهرية صغيرة، 3-7% أخطاء تصنيف على إيميلات حدّية، اعتماد على خدمتين خارجيتين (Anthropic + Google) — لو أي واحدة منهم وقعت، السكربت بيفشل.

أهم trade-off عملي: السكربت بيقرأ snippet فقط (أول ~200 حرف من body) عبر format="metadata". ده بيوفّر 85% من التوكنز، مقابل 2-3% دقة أقل على إيميلات طويلة ومبهمة من أول سطر. لو محتاج دقة أعلى، غيّر الـ format لـ full وخد أول 2000 حرف من الـ body — التكلفة هتقفز لحوالي $8-10/شهر.

متى لا تستخدم هذه الطريقة

لو inbox بتاعك أقل من 20 إيميل يوميًا، فلاتر Gmail الأصلية كفاية — مش محتاج LLM. لو بتشتغل على إيميلات فيها PII أو PHI خاضعة لـ GDPR/HIPAA ومش مسموح تبعتها لـ API خارجي، الحل ده مش مناسب — استخدم موديل local زي Llama 3 عبر Ollama. ولو بتحاول تلخّص محتوى الإيميل أو ترد تلقائيًا، ده use case مختلف تمامًا (summarization أو generation)، ومينفعش تعمله بنفس الـ prompt الصغير.

الخطوة التالية

انسخ السكربت، عدّل قاموس LABELS لفئاتك انت، وشغّله يدويًا على 10 إيميلات فقط أول مرة (maxResults=10). قيّم النتيجة بعينك: لو الدقة فوق 90%، حطّه في cron. لو أقل، حسّن وصف كل label داخل القاموس — الوصف هو اللي بيفرّق، مش اسم الـ label.

المصادر

  • Gmail API Usage limits — Google for Developers
  • Claude Haiku 4.5 — Anthropic
  • Gmail API Python Quickstart — Google
  • Claude API Pricing — platform.claude.com
  • Prompt Caching — Anthropic Docs

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة