0Pricing
AI Agents · Lektion

E-Mails programmgesteuert lesen und senden

Nachrichten auflisten, den Nachrichteninhalt abrufen und MIME-E-Mails versenden.

E-Mails programmgesteuert lesen und senden ist eine kostenlose AI Agents-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Agents-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.

Nachrichten mit der Gmail API auflisten

Der erste Schritt beim Lesen von E-Mails besteht darin, Nachrichten aufzulisten, die Ihren Kriterien entsprechen. service.users().messages().list() gibt Nachrichten-IDs und Thread-IDs zurück – nicht den vollständigen Inhalt. Anschließend rufen Sie jede Nachricht einzeln ab. Durch dieses zweistufige Muster bleibt der Aufruf zum Auflisten schnell.

def list_messages(service, user_id='me', query='', max_results=10):
    results = service.users().messages().list(
        userId=user_id,
        q=query,          # Gmail search query
        maxResults=max_results
    ).execute()

    messages = results.get('messages', [])
    print(f'Found {len(messages)} messages')
    return messages

# Examples of Gmail search queries:
# 'is:unread' — unread messages
# 'from:boss@company.com is:unread' — unread from boss
# 'subject:invoice label:inbox' — invoices in inbox
# 'after:2026/05/01 has:attachment' — recent with attachments
messages = list_messages(gmail_service, query='is:unread label:inbox')

Eine vollständige Nachricht abrufen

Verwenden Sie service.users().messages().get(), um den vollständigen Nachrichteninhalt abzurufen. Der Parameter format steuert, wie viele Daten zurückgegeben werden: 'full' enthält Header und Textkörper, 'metadata' gibt nur Header zurück und 'minimal' nur IDs und Labels.

def get_message(service, message_id, user_id='me'):
    message = service.users().messages().get(
        userId=user_id,
        id=message_id,
        format='full'  # 'full', 'metadata', or 'minimal'
    ).execute()
    return message

# Fetch the first unread message
messages = list_messages(gmail_service, query='is:unread', max_results=1)
if messages:
    msg = get_message(gmail_service, messages[0]['id'])
    print('Thread ID:', msg['threadId'])
    print('Labels:', msg['labelIds'])
    print('Snippet:', msg['snippet'][:100])

E-Mail-Header extrahieren

Header (From, To, Subject, Date) werden in message['payload']['headers'] als Liste von {'name': ..., 'value': ...}-Dictionaries gespeichert. Schreiben Sie eine Hilfsfunktion, die Header nach Namen extrahiert – Sie werden sie ständig verwenden.

def get_header(message, name):
    headers = message.get('payload', {}).get('headers', [])
    for h in headers:
        if h['name'].lower() == name.lower():
            return h['value']
    return ''

def extract_email_meta(message):
    return {
        'id': message['id'],
        'from': get_header(message, 'From'),
        'to': get_header(message, 'To'),
        'subject': get_header(message, 'Subject'),
        'date': get_header(message, 'Date'),
        'snippet': message.get('snippet', '')
    }

meta = extract_email_meta(msg)
print(f'From: {meta["from"]}')
print(f'Subject: {meta["subject"]}')
print(f'Date: {meta["date"]}')

E-Mail-Body decodieren (base64)

E-Mail-Bodies sind in der Gmail API base64url-codiert – eine URL-sichere Variante von base64, bei der + zu - und / zu _ wird. Verwenden Sie zum Decodieren base64.urlsafe_b64decode(). Behandeln Sie sowohl einfache E-Mails mit einem Teil als auch Multipart-E-Mails.

import base64

def decode_body(data):
    if not data:
        return ''
    decoded_bytes = base64.urlsafe_b64decode(data + '==')
    return decoded_bytes.decode('utf-8', errors='replace')

def get_email_body(message):
    payload = message.get('payload', {})
    mime_type = payload.get('mimeType', '')

    # Simple (non-multipart) email
    if 'body' in payload and payload['body'].get('data'):
        return decode_body(payload['body']['data'])

    # Multipart email: find the text/plain or text/html part
    parts = payload.get('parts', [])
    for part in parts:
        if part.get('mimeType') == 'text/plain':
            return decode_body(part['body'].get('data', ''))

    # Fallback: try text/html
    for part in parts:
        if part.get('mimeType') == 'text/html':
            return decode_body(part['body'].get('data', ''))

    return message.get('snippet', '')

# --- demo ---
encoded = base64.urlsafe_b64encode(b'Hello from the agent!').decode().rstrip('=')
print('Decoded body:', decode_body(encoded))

message = {
    'payload': {
        'mimeType': 'multipart/alternative',
        'parts': [
            {'mimeType': 'text/plain', 'body': {'data': encoded}}
        ]
    }
}
print('Email body:', get_email_body(message))

Multipart-E-Mails rekursiv verarbeiten

Komplexe E-Mails (mit Anhängen, Inline-Bildern oder gemischten Inhalten) bestehen aus verschachtelten Multipart-Strukturen. Die Textteile können beliebig tief verschachtelt sein. Eine rekursive Funktion, die den Teilbaum durchläuft, verarbeitet alle Fälle.

import base64

def extract_parts(payload, target_mime='text/plain'):
    parts_text = []
    mime_type = payload.get('mimeType', '')

    if mime_type == target_mime:
        data = payload.get('body', {}).get('data', '')
        if data:
            decoded = base64.urlsafe_b64decode(data + '==').decode('utf-8', errors='replace')
            parts_text.append(decoded)

    # Recurse into sub-parts
    for part in payload.get('parts', []):
        parts_text.extend(extract_parts(part, target_mime))

    return parts_text

def get_plain_text(message):
    payload = message.get('payload', {})
    texts = extract_parts(payload, 'text/plain')
    return '\n\n'.join(texts) if texts else message.get('snippet', '')

body_text = get_plain_text(msg)
print(f'Body ({len(body_text)} chars):', body_text[:200])

Nachrichten als gelesen markieren

Nach der Verarbeitung einer E-Mail sollte Ihr Agent sie als gelesen markieren, indem er das Label UNREAD entfernt. Verwenden Sie service.users().messages().modify() mit removeLabelIds=['UNREAD']. Sie können auch Labels wie PROCESSED hinzufügen, um von einem Agenten bearbeitete E-Mails zu verfolgen.

def mark_as_read(service, message_id, user_id='me'):
    service.users().messages().modify(
        userId=user_id,
        id=message_id,
        body={'removeLabelIds': ['UNREAD']}
    ).execute()
    print(f'Marked {message_id} as read')

def add_label(service, message_id, label_id, user_id='me'):
    service.users().messages().modify(
        userId=user_id,
        id=message_id,
        body={'addLabelIds': [label_id]}
    ).execute()

# Get label ID by name
def get_label_id(service, label_name, user_id='me'):
    labels = service.users().labels().list(userId=user_id).execute()
    for label in labels.get('labels', []):
        if label['name'].lower() == label_name.lower():
            return label['id']
    return None

# --- demo: minimal stand-in for the Gmail API's service object ---
class _Exec:
    def __init__(self, result):
        self._result = result
    def execute(self):
        return self._result

class _FakeUsers:
    def messages(self):
        return self
    def modify(self, **kwargs):
        print(f'[gmail api] messages.modify({kwargs})')
        return _Exec({'id': kwargs.get('id')})
    def labels(self):
        return self
    def list(self, **kwargs):
        return _Exec({'labels': [{'id': 'Label_1', 'name': 'Processed'}]})

class _FakeService:
    def users(self):
        return _FakeUsers()

service = _FakeService()
mark_as_read(service, 'msg_42')
add_label(service, 'msg_42', 'Label_1')
print('Label id for "Processed":', get_label_id(service, 'Processed'))

E-Mail mit MIMEText erstellen

Um eine E-Mail zu senden, erstellen Sie sie zunächst als MIME-Nachricht mit der standardmäßigen Python-Bibliothek email. Codieren Sie anschließend die Rohbytes mit base64url und senden Sie sie per POST an die Gmail API. MIMEText übernimmt die korrekte Codierung des Nachrichteninhalts.

import base64
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def create_message(sender, to, subject, body_text, body_html=None):
    if body_html:
        msg = MIMEMultipart('alternative')
        msg.attach(MIMEText(body_text, 'plain', 'utf-8'))
        msg.attach(MIMEText(body_html, 'html', 'utf-8'))
    else:
        msg = MIMEText(body_text, 'plain', 'utf-8')

    msg['From'] = sender
    msg['To'] = to
    msg['Subject'] = subject

    # Encode as base64url
    raw = base64.urlsafe_b64encode(msg.as_bytes()).decode('utf-8')
    return {'raw': raw}

message = create_message(
    sender='agent@yourcompany.com',
    to='recipient@example.com',
    subject='Weekly Summary',
    body_text='Hello,\n\nHere is your summary.\n\nBest,\nAgent'
)

# --- demo ---
print('Message keys:', list(message.keys()))
print('Base64 length:', len(message['raw']))

E-Mail mit der Gmail API senden

Senden Sie die erstellte Nachricht mit service.users().messages().send(). Der Parameter userId='me' verweist auf den authentifizierten Benutzer. Die API gibt die gesendete Nachricht mit ihrer ID und Thread-ID zurück.

from googleapiclient.errors import HttpError

def send_message(service, message, user_id='me'):
    try:
        sent = service.users().messages().send(
            userId=user_id,
            body=message
        ).execute()
        print(f'Message sent! ID: {sent["id"]}')
        return sent
    except HttpError as e:
        import json
        body = json.loads(e.content.decode())
        print(f'Send failed ({e.resp.status}): {body.get("error", {}).get("message")}')
        return None

# Send the message
message = create_message(
    sender='me',
    to='team@company.com',
    subject='Agent Report',
    body_text='Processing complete. 42 tasks handled.'
)
send_message(gmail_service, message)

E-Mail-Entwürfe erstellen und versenden

Statt sie sofort zu senden, können Agenten Entwürfe zur Prüfung durch einen Menschen erstellen. Verwenden Sie service.users().drafts().create(). Ein Mensch kann den Entwurf anschließend in der Gmail-Oberfläche prüfen und senden. Dies ist das empfohlene Muster für jede E-Mail, die eine menschliche Freigabe erfordert.

def create_draft(service, message, user_id='me'):
    draft = service.users().drafts().create(
        userId=user_id,
        body={'message': message}
    ).execute()
    print(f'Draft created: {draft["id"]}')
    return draft

def send_draft(service, draft_id, user_id='me'):
    sent = service.users().drafts().send(
        userId=user_id,
        body={'id': draft_id}
    ).execute()
    print(f'Draft sent as message: {sent["id"]}')
    return sent

# Create a draft for review
message = create_message(
    sender='me',
    to='client@example.com',
    subject='Proposal Follow-up',
    body_text='Dear Client,\n\nFollowing up on our proposal...'
)
draft = create_draft(gmail_service, message)
# Human reviews in Gmail, then agent sends:
# send_draft(gmail_service, draft['id'])

Mehrere E-Mails stapelweise verarbeiten

Wenn Sie viele E-Mails verarbeiten, rufen Sie sie nicht in einer engen Schleife einzeln ab – sonst überschreiten Sie die Kontingente. Verwenden Sie eine kontrollierte Schleife mit kurzen Pausen oder die Batch-Request-Funktion der Gmail API, um mehrere Vorgänge in einem einzigen HTTP-Aufruf zu bündeln.

import time

def process_unread_emails(service, max_emails=20):
    messages = list_messages(
        service,
        query='is:unread label:inbox',
        max_results=max_emails
    )

    processed = []
    for i, msg_ref in enumerate(messages):
        # Rate-limit: process max 5 per second
        if i > 0 and i % 5 == 0:
            time.sleep(1)

        msg = get_message(service, msg_ref['id'])
        meta = extract_email_meta(msg)
        body = get_plain_text(msg)

        result = {
            'id': msg['id'],
            'from': meta['from'],
            'subject': meta['subject'],
            'body_preview': body[:200]
        }
        processed.append(result)
        mark_as_read(service, msg['id'])

    return processed

Auf eine E-Mail antworten (im Thread)

Um eine Antwort innerhalb eines Threads zu senden, setzen Sie die Header In-Reply-To und References auf den Message-ID-Header der ursprünglichen Nachricht und übergeben Sie die threadId an den Sendeaufruf. Dadurch bleibt die Antwort im selben Gmail-Konversationsthread.

import base64
from email.mime.text import MIMEText

def create_reply(original_message, reply_text, sender='me'):
    original_msg_id = get_header(original_message, 'Message-ID')
    to = get_header(original_message, 'From')
    subject = get_header(original_message, 'Subject')
    if not subject.startswith('Re:'):
        subject = 'Re: ' + subject

    msg = MIMEText(reply_text, 'plain', 'utf-8')
    msg['From'] = sender
    msg['To'] = to
    msg['Subject'] = subject
    msg['In-Reply-To'] = original_msg_id
    msg['References'] = original_msg_id

    raw = base64.urlsafe_b64encode(msg.as_bytes()).decode('utf-8')
    return {
        'raw': raw,
        'threadId': original_message['threadId']  # keeps it in thread
    }

Schnelltest: base64-E-Mail-Body

Testen Sie Ihr Verständnis der Nachrichtenverarbeitung mit der Gmail API.

Zusammenfassung: E-Mails lesen und senden

Ihr Agent kann nun E-Mails programmgesteuert lesen und senden:

  • Auflisten: messages().list(q='is:unread') gibt IDs zurück; verwenden Sie die Gmail-Syntax für Suchanfragen
  • Abrufen: messages().get(id=..., format='full') gibt die vollständige Nachricht zurück
  • Header analysieren: From/Subject/Date aus payload.headers extrahieren
  • Body decodieren: base64.urlsafe_b64decode(data) für Text verwenden; Multipart-Teile rekursiv durchlaufen
  • Senden: mit MIMEText erstellen, mit base64url codieren und per messages().send() als POST senden
  • Im Thread antworten: den Header In-Reply-To sowie threadId im Sendekörper setzen

Häufig gestellte Fragen

Ist die Lektion „E-Mails programmgesteuert lesen und senden“ kostenlos?

Ja — der vollständige Text von „E-Mails programmgesteuert lesen und senden“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Agents-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Agents-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „E-Mails programmgesteuert lesen und senden“?

Nachrichten auflisten, den Nachrichteninhalt abrufen und MIME-E-Mails versenden. Du übst AI Agents mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um AI Agents zu starten?

Keine Vorkenntnisse erforderlich. AI Agents auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „E-Mails programmgesteuert lesen und senden“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser AI Agents-Lektion Code schreiben und ausführen?

Ja. Jede AI Agents-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Über die API mit Gmail verbinden
  2. E-Mails programmgesteuert lesen und senden
  3. Kalenderereignisse erstellen und abfragen
  4. Einen einfachen E-Mail-Assistenten als Agent erstellen
← Zurück zu AI Agents