Läsa och skicka e-post programmatiskt
Lista meddelanden, hämta meddelandetext och skicka MIME-e-post.
Läsa och skicka e-post programmatiskt är en gratis lektion i AI-agenter på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för AI-agenter, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i AI-agenter innehåller totalt 4 lektioner.
Lista meddelanden med Gmail API
Det första steget när Ni läser e-post är att lista meddelanden som matchar Era kriterier. service.users().messages().list() returnerar meddelande-ID:n och tråd-ID:n — inte hela innehållet. Därefter hämtar Ni varje meddelande separat. Detta tvåstegsmönster håller listanropet snabbt.
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')Hämta ett komplett meddelande
Använd service.users().messages().get() för att hämta hela meddelandets innehåll. Parametern format styr hur mycket data som returneras: 'full' innehåller rubriker och brödtext, 'metadata' returnerar endast rubriker och 'minimal' returnerar bara ID:n och etiketter.
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])Extrahera e-postrubriker
Rubrikerna (From, To, Subject, Date) lagras i message['payload']['headers'] som en lista med ordböcker av typen {'name': ..., 'value': ...}. Skriv en hjälpfunktion som extraherar rubriker efter namn — Ni kommer att använda den hela tiden.
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"]}')Avkoda e-postens brödtext (base64)
E-postens brödtext i Gmail API är base64url-kodad — en URL-säker variant av base64 där + blir - och / blir _. Använd base64.urlsafe_b64decode() för att avkoda den. Hantera både enkla e-postmeddelanden (med en del) och meddelanden med flera delar.
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))
Hantera e-postmeddelanden med flera delar rekursivt
Komplexa e-postmeddelanden (med bilagor, infogade bilder eller blandat innehåll) består av kapslade strukturer med flera delar. Brödtextdelarna kan vara kapslade på godtyckligt djup. En rekursiv funktion som går igenom delträdet hanterar alla fall.
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])Markera meddelanden som lästa
När agenten har behandlat ett e-postmeddelande bör den markera det som läst genom att ta bort etiketten UNREAD. Använd service.users().messages().modify() med removeLabelIds=['UNREAD']. Ni kan även lägga till etiketter som PROCESSED för att hålla reda på e-postmeddelanden som agenten har hanterat.
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'))
Skapa e-post med MIMEText
För att skicka e-post skapar Ni först ett MIME-meddelande med Pythons standardbibliotek email. Base64url-koda sedan de råa byten och skicka dem med POST till Gmail API. MIMEText hanterar korrekt kodning av meddelandets brödtext.
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']))
Skicka e-post med Gmail API
Skicka det skapade meddelandet med service.users().messages().send(). Parametern userId='me' syftar på den autentiserade användaren. API:t returnerar det skickade meddelandet med dess ID och tråd-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)Skapa och skicka e-postutkast
I stället för att skicka meddelanden direkt kan agenter skapa utkast för mänsklig granskning. Använd service.users().drafts().create(). Därefter kan en människa granska och skicka utkastet från Gmail-gränssnittet. Detta är det rekommenderade mönstret för all e-post som kräver mänskligt godkännande.
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'])Bearbeta flera e-postmeddelanden i batch
När Ni behandlar många e-postmeddelanden bör Ni inte hämta dem ett i taget i en tät loop — då riskerar Ni att nå kvotgränserna. Använd en kontrollerad loop med korta fördröjningar eller Gmail APIs funktion för batchförfrågningar för att samla flera åtgärder i ett enda HTTP-anrop.
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 processedSvara på ett e-postmeddelande (i tråden)
För att skicka ett svar i samma tråd anger Ni rubrikerna In-Reply-To och References till det ursprungliga meddelandets rubrik Message-ID och skickar med threadId i sändningsanropet. Då förblir svaret i samma Gmail-konversationstråd.
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
}Snabbtest: e-postens base64-brödtext
Testa Er förståelse av meddelandehantering i Gmail API.
Sammanfattning: läsa och skicka e-post
Er agent kan nu läsa och skicka e-post programmatiskt:
- Lista:
messages().list(q='is:unread')returnerar ID:n; använd Gmails söksyntax - Hämta:
messages().get(id=..., format='full')returnerar hela meddelandet - Tolka rubriker: extrahera From/Subject/Date från
payload.headers - Avkoda brödtexten:
base64.urlsafe_b64decode(data)för text; gå rekursivt igenom delar med flera delar - Skicka: skapa med
MIMEText, base64url-koda och skicka med POST viamessages().send() - Svara i tråden: ange rubriken
In-Reply-To+threadIdi sändningsinnehållet
Lär dig AI-agenter med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 60
- Lektioner
- 239
Vanliga frågor
Är lektionen ”Läsa och skicka e-post programmatiskt” gratis?
Ja – hela texten till ”Läsa och skicka e-post programmatiskt” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i AI-agenter, kan Ni uppgradera till CoddyKit PRO. Kursen i AI-agenter innehåller totalt 4 lektioner.
Vad lär jag mig i ”Läsa och skicka e-post programmatiskt”?
Lista meddelanden, hämta meddelandetext och skicka MIME-e-post. Ni övar på AI-agenter med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig AI-agenter?
Du behöver inga förkunskaper. Utbildningen i AI-agenter på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Läsa och skicka e-post programmatiskt”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här AI-agenter-lektionen?
Ja. Varje AI-agenter-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Anslut till Gmail via API:t
- Läsa och skicka e-post programmatiskt
- Skapa och söka efter kalenderhändelser
- Skapa en enkel e-postassistentagent