E-mails programmatisch lezen en verzenden
Berichten opsommen, de berichttekst ophalen en MIME-e-mails verzenden.
E-mails programmatisch lezen en verzenden is een gratis AI-agenten-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject AI-agenten. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus AI-agenten bevat in totaal 4 lessen.
Berichten opsommen met de Gmail API
De eerste stap bij het lezen van e-mail is het opsommen van berichten die aan je criteria voldoen. service.users().messages().list() retourneert bericht-ID's en gespreksreeks-ID's — niet de volledige inhoud. Vervolgens haal je elk bericht afzonderlijk op. Dit patroon in twee stappen houdt de lijstaanroep snel.
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')Een volledig bericht ophalen
Gebruik service.users().messages().get() om de volledige berichtinhoud op te halen. De parameter format bepaalt hoeveel gegevens worden geretourneerd: 'full' bevat koppen en tekst, 'metadata' retourneert alleen koppen en 'minimal' retourneert alleen ID's en 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-mailkoppen extraheren
Koppen (From, To, Subject, Date) worden opgeslagen in message['payload']['headers'] als een lijst met woordenboeken van het type {'name': ..., 'value': ...}. Schrijf een hulpfunctie om koppen op naam te extraheren — je gebruikt deze voortdurend.
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"]}')De e-mailtekst decoderen (base64)
E-mailteksten in de Gmail API zijn gecodeerd in base64url — een URL-veilige variant van base64 waarbij + verandert in - en / verandert in _. Gebruik base64.urlsafe_b64decode() om te decoderen. Verwerk zowel eenvoudige (enkelvoudige) als meerdelige 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))
Meerdelige e-mails recursief afhandelen
Complexe e-mails (met bijlagen, inlineafbeeldingen of gemengde inhoud) bestaan uit geneste structuren met meerdere onderdelen. De onderdelen van de berichttekst kunnen willekeurig diep genest zijn. Een recursieve functie die de onderdelenboom doorloopt, verwerkt alle gevallen.
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])Berichten als gelezen markeren
Na het verwerken van een e-mail moet je agent deze als gelezen markeren door het label UNREAD te verwijderen. Gebruik service.users().messages().modify() met removeLabelIds=['UNREAD']. Je kunt ook labels zoals PROCESSED toevoegen om bij te houden welke e-mails door de agent zijn verwerkt.
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 opstellen met MIMEText
Als je een e-mail wilt verzenden, stel je deze eerst op als MIME-bericht met de standaardbibliotheek email van Python. Codeer de onbewerkte bytes vervolgens in base64url en verstuur ze met POST naar de Gmail API. MIMEText zorgt voor de juiste codering van de berichttekst.
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 verzenden met de Gmail API
Verzend het opgestelde bericht met service.users().messages().send(). De parameter userId='me' verwijst naar de geauthenticeerde gebruiker. De API retourneert het verzonden bericht met de bericht-ID en gespreksreeks-ID.
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)Concept-e-mails maken en verzenden
In plaats van berichten direct te verzenden, kunnen agents concepten maken die door een mens worden gecontroleerd. Gebruik service.users().drafts().create(). Een mens kan het concept vervolgens controleren en vanuit de gebruikersinterface van Gmail verzenden. Dit is de aanbevolen aanpak voor e-mail waarvoor menselijke goedkeuring nodig is.
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'])Meerdere e-mails in batches verwerken
Wanneer je veel e-mails verwerkt, haal je ze niet één voor één op in een strakke lus — anders bereik je de quotumlimieten. Gebruik een beheersbare lus met korte vertragingen of de functie voor batchverzoeken van de Gmail API om meerdere bewerkingen in één HTTP-aanroep te bundelen.
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 processedEen e-mail beantwoorden (binnen dezelfde gespreksreeks)
Als je een antwoord binnen dezelfde gespreksreeks wilt verzenden, stel je de koppen In-Reply-To en References in op de kop Message-ID van het oorspronkelijke bericht en geef je threadId door aan de verzendaanroep. Zo blijft het antwoord in hetzelfde Gmail-gesprek staan.
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
}Korte toets: e-mailtekst in base64
Toets je begrip van het verwerken van Gmail API-berichten.
Overzicht van e-mails lezen en verzenden
Je agent kan nu programmatisch e-mails lezen en verzenden:
- Opsommen:
messages().list(q='is:unread')retourneert ID's; gebruik de zoeksyntaxis van Gmail - Ophalen:
messages().get(id=..., format='full')retourneert het volledige bericht - Koppen ontleden: extraheer From, Subject en Date uit
payload.headers - Berichttekst decoderen: gebruik
base64.urlsafe_b64decode(data)voor tekst en doorloop meerdelige onderdelen recursief - Verzenden: stel het bericht op met
MIMEText, codeer het in base64url en verstuur het met POST viamessages().send() - Antwoorden binnen een gespreksreeks: stel de kop
In-Reply-Toin en voegthreadIdtoe aan de verzendgegevens
Leer AI-agenten met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 60
- Lessen
- 239
Veelgestelde vragen
Is de les “E-mails programmatisch lezen en verzenden” gratis?
Ja — de volledige tekst van “E-mails programmatisch lezen en verzenden” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus AI-agenten wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus AI-agenten bevat in totaal 4 lessen.
Wat leer ik in “E-mails programmatisch lezen en verzenden”?
Berichten opsommen, de berichttekst ophalen en MIME-e-mails verzenden. Je oefent met AI-agenten door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met AI-agenten te beginnen?
Ervaring vooraf is niet nodig. AI-agenten op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “E-mails programmatisch lezen en verzenden”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over AI-agenten?
Ja. Elke les over AI-agenten bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Via de API verbinding maken met Gmail
- E-mails programmatisch lezen en verzenden
- Agenda-afspraken maken en opvragen
- Een eenvoudige e-mailassistent-agent bouwen