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

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

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

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

المنصة

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

الدعم

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

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

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

أتمتة استخراج فواتير Gmail إلى Google Sheets بـ Claude Haiku — تتبّع مصاريفك بدون ما تفتح إيميل

📅 ٢٠ أبريل ٢٠٢٦⏱ 6 دقائق قراءة
أتمتة استخراج فواتير Gmail إلى Google Sheets بـ Claude Haiku — تتبّع مصاريفك بدون ما تفتح إيميل

لو بتشتغل فريلانسر أو بتدير شركة صغيرة وبتقضي آخر كل شهر ساعتين بتفتح فواتير AWS و Vercel و Claude و GitHub و Notion واحدة واحدة، السكربت اللي هنا هيخلي العملية دي 45 ثانية أوتوماتيك.

أتمتة استخراج فواتير Gmail إلى Google Sheets بـ Claude Haiku

الفكرة ببساطة: سكربت Python بيمرّ على Gmail، يدوّر على الإيميلات اللي فيها فاتورة آخر 30 يوم، يبعت محتواها لـ Claude Haiku 4.5 علشان يطلّع منها البيانات المنظمة (رقم الفاتورة، المورد، المبلغ، التاريخ، العملة)، ويضيف سطر في Google Sheet مخصص. كل ده بتكلفة أقل من 70 سنت في الشهر لو عندك 150 فاتورة.

فواتير ورقية متراكمة بجانب حاسبة ولوح مفاتيح يمثّل الفوضى اللي بتحلها الأتمتة

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

لما تفتح Gmail في آخر الشهر هتلاقي 40-80 إيميل فاتورة متفرّقة بين نوتيفيكيشن وإعلانات. كل فاتورة لازم تاخدها وتكتبها يدوي في شيت. اللي بيحصل فعلاً:

  • بتنسى فاتورة أو اتنين كل شهر، وبيبان الفرق في الضرايب.
  • بتاخد من 90 لـ 120 دقيقة في الجمع، 70% منهم نسخ ولصق بلا قيمة.
  • لو عندك محاسب خارجي، بتبعته شيت ناقص فبيرجعلك بأسئلة.

الحل مش "استخدم QuickBooks"، الحل إنك تأتمت الجزء اللي القالب بتاعه ثابت: البيانات جوه الإيميل نفسه.

المفهوم قبل ما ندخل في الكود: يعني إيه Structured Extraction؟

تخيّل إن عندك سكرتير جديد، جاهل تمامًا بالمحاسبة. بتديله كومة من 50 ورقة مخلوطة وبتقوله: "اقرا كل ورقة، ولو ده فاتورة، اكتب في الدفتر ده اسم الشركة، الرقم، والمبلغ". السكرتير مش لازم يفهم الضرايب. هو بس بيتعرّف على النمط ويحوّله لصفوف.

ده بالظبط اللي Claude Haiku بيعمله معاك. بنبعتله النص الخام للإيميل، وبنقوله: "رجّع لي JSON بالشكل ده بالظبط: {vendor, invoice_number, amount, currency, date, due_date}". لو الإيميل مش فاتورة أصلاً، بيرجّع null. ده اسمه Structured Extraction — استخراج بيانات منظمة من نص غير منظم.

علميًا: بنستخدم tool calling في Claude API مع JSON schema محدد، فالنموذج ملزم يرجّع output يطابق الـ schema. ده بيقلل hallucination لأقل من 1% على نصوص فيها بيانات واضحة زي الفواتير.

إعداد البيئة في 5 خطوات

  1. فعّل Gmail API من Google Cloud Console وحمّل ملف credentials.json.
  2. فعّل Google Sheets API على نفس الـ project.
  3. اعمل Service Account وشارك الـ Sheet معاه بصلاحية Editor.
  4. خد API key من console.anthropic.com.
  5. ثبّت المكتبات:
Bash
pip install anthropic google-auth google-auth-oauthlib \
  google-api-python-client gspread python-dotenv
كود Python يعمل على شاشة بلون داكن يمثّل سكربت الأتمتة المتصل بـ Gmail API

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

الكود ده بيسحب إيميلات آخر 30 يوم فيها كلمات زي "invoice"، "فاتورة"، "receipt"، يستخرج البيانات، ويدفعها للـ Sheet:

Python
import base64
import json
import os
from datetime import datetime, timedelta

import anthropic
import gspread
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build

GMAIL_QUERY = 'newer_than:30d (invoice OR فاتورة OR receipt OR billing)'
SHEET_ID = os.environ['SHEET_ID']
MODEL = 'claude-haiku-4-5-20251001'

client = anthropic.Anthropic()
gc = gspread.service_account(filename='service_account.json')
sheet = gc.open_by_key(SHEET_ID).sheet1

EXTRACT_TOOL = [{
    'name': 'save_invoice',
    'description': 'احفظ بيانات فاتورة مستخرجة من إيميل.',
    'input_schema': {
        'type': 'object',
        'properties': {
            'is_invoice': {'type': 'boolean'},
            'vendor': {'type': 'string'},
            'invoice_number': {'type': 'string'},
            'amount': {'type': 'number'},
            'currency': {'type': 'string'},
            'issue_date': {'type': 'string'},
            'due_date': {'type': 'string'}
        },
        'required': ['is_invoice']
    }
}]

def extract_invoice(email_text: str) -> dict | None:
    msg = client.messages.create(
        model=MODEL,
        max_tokens=512,
        tools=EXTRACT_TOOL,
        tool_choice={'type': 'tool', 'name': 'save_invoice'},
        messages=[{
            'role': 'user',
            'content': f'استخرج بيانات الفاتورة من الإيميل ده. '
                       f'لو مش فاتورة، رجّع is_invoice=false.\n\n{email_text[:6000]}'
        }]
    )
    for block in msg.content:
        if block.type == 'tool_use':
            data = block.input
            return data if data.get('is_invoice') else None
    return None

def fetch_emails():
    creds = Credentials.from_authorized_user_file('token.json')
    gmail = build('gmail', 'v1', credentials=creds)
    resp = gmail.users().messages().list(
        userId='me', q=GMAIL_QUERY, maxResults=200
    ).execute()
    for ref in resp.get('messages', []):
        msg = gmail.users().messages().get(
            userId='me', id=ref['id'], format='full'
        ).execute()
        yield parse_email_body(msg)

def parse_email_body(msg) -> str:
    for part in msg['payload'].get('parts', [msg['payload']]):
        if part['mimeType'] in ('text/plain', 'text/html'):
            data = part['body'].get('data', '')
            return base64.urlsafe_b64decode(data).decode('utf-8', 'ignore')
    return ''

def run():
    seen = {row[1] for row in sheet.get_all_values()[1:] if len(row) > 1}
    new_rows = []
    for body in fetch_emails():
        invoice = extract_invoice(body)
        if not invoice or invoice['invoice_number'] in seen:
            continue
        new_rows.append([
            invoice.get('vendor', ''),
            invoice.get('invoice_number', ''),
            invoice.get('amount', 0),
            invoice.get('currency', 'USD'),
            invoice.get('issue_date', ''),
            invoice.get('due_date', ''),
        ])
    if new_rows:
        sheet.append_rows(new_rows)
    print(f'تم إضافة {len(new_rows)} فاتورة جديدة')

if __name__ == '__main__':
    run()

شغّله بـ cron يومي الساعة 7 الصبح:

Bash
0 7 * * * cd /home/you/invoices && /usr/bin/python3 main.py >> run.log 2>&1

إزاي يعمل الاستخراج فعلاً؟ مثال حقيقي

لو وصلك إيميل من AWS نصّه:

"Your AWS Invoice for March 2026 is ready. Invoice number: 9876543210. Amount: $247.33 USD. Due: 2026-04-15."

Claude Haiku بيرجّع:

JSON
{
  "is_invoice": true,
  "vendor": "AWS",
  "invoice_number": "9876543210",
  "amount": 247.33,
  "currency": "USD",
  "issue_date": "2026-03-31",
  "due_date": "2026-04-15"
}

السكربت بيلاقي إن 9876543210 مش موجود في الشيت قبل كده، فبيضيف الصف. لو دخّلت نفس الإيميل مرتين، الـ deduplication على invoice_number بيمنع التكرار.

شاشة لابتوب تعرض جدول Google Sheets بسطور بيانات فواتير مستخرجة تلقائيًا

التكلفة بالأرقام

على 150 إيميل شهريًا، متوسط 800 token لكل إيميل (input) و 120 token للـ output:

  • Input: 150 × 800 = 120K token × 1 دولار / مليون = 0.12 دولار
  • Output: 150 × 120 = 18K token × 5 دولار / مليون = 0.09 دولار
  • Gmail + Sheets API: مجانًا تحت الحدود اليومية
  • الإجمالي: ~0.21 دولار شهريًا لو 150 إيميل، و ~0.70 دولار لو 500 إيميل

لو Claude Haiku رفض يستخرج فاتورة (أول is_invoice=false)، مش بتتسجل في الشيت. في تجربتي، الدقة ~96% على فواتير الـ SaaS الشهيرة، و ~88% على فواتير مصرية بالعربي فيها صور أكتر من نص.

Trade-offs لازم تعرفها قبل ما تشغّل

  • الخصوصية: نص الإيميل بيطلع لـ Anthropic API. لو فيه عقود سرية للعملاء، استخدم --data-usage=opt-out في الطلب أو شغّل النموذج self-hosted على حاجة زي Llama 3.
  • الفواتير اللي صور بس: Claude Haiku بيقرأ صور، بس الـ token cost بيقفز 3-5 مرات. لو الشركة بتبعت PDF attachment بدون نص في الإيميل، هتحتاج step إضافي لـ OCR.
  • المورّدين الجداد: أول مرة بيجي ايميل من شركة مش متعرف عليها، راجع الصف يدوي. بعد أول 5 فواتير من نفس الشركة، الدقة بتثبت.
  • Rate Limits: Gmail API بيقبل 250 مستخدم-كودا في الثانية. لو عندك 2000 إيميل في الشهر، قسّمهم على batches بـ time.sleep(0.5) بين الاستدعاءات.

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

السكربت ده مش مناسب في الحالات دي:

  • لو محاسبتك مربوطة بـ ERP زي SAP — اربط الـ ERP مباشرة بـ API المورّد، لا تمر بـ Gmail.
  • لو محتاج توافق SOC 2 أو HIPAA من غير zero data retention contract — اتصل بمبيعات Anthropic أولًا.
  • لو الفواتير حصرًا PDF attached من غير نص في جسم الإيميل — هتحتاج pipeline تاني فيه pdfplumber قبل ما توصل لـ Claude.
  • لو بتتعامل مع أقل من 10 فواتير شهريًا — الإعداد الأولي (ساعة) أطول من اللي هتوفّره.

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

افتح Google Cloud Console دلوقتي، اعمل project جديد اسمه invoice-bot، فعّل Gmail و Sheets APIs، وحمّل الـ credentials.json. انسخ السكربت فوق كما هو، ضيف API key بتاع Anthropic في .env، وشغّل python main.py مرة واحدة يدوي. لو اتضافت فاتورة واحدة صح للشيت، الباقي cron وخلاص. لو واجهت مشكلة في scope الصلاحيات، غالبًا ناسي https://www.googleapis.com/auth/gmail.readonly في الـ OAuth consent screen.

المصادر

  • Anthropic — Tool use with Claude
  • Gmail API Guides
  • Google Sheets API Python Quickstart
  • gspread — Python client for Google Sheets
  • Anthropic Pricing (Haiku 4.5)
  • Gmail search query syntax

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

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

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