Membaca dan Mengirim Email Secara Terprogram
Mencantumkan pesan, mengambil isi pesan, dan mengirim email MIME.
Membaca dan Mengirim Email Secara Terprogram adalah pelajaran AI Agents gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Agents, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Agents mencakup 4 pelajaran total.
Membuat Daftar Pesan dengan Gmail API
Langkah pertama untuk membaca email adalah membuat daftar pesan yang sesuai dengan kriteria Anda. service.users().messages().list() mengembalikan ID pesan dan ID rangkaian percakapan — bukan konten lengkapnya. Selanjutnya, ambil setiap pesan secara terpisah. Pola dua langkah ini membuat panggilan pembuatan daftar tetap cepat.
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')Mengambil Pesan Lengkap
Gunakan service.users().messages().get() untuk mengambil konten pesan lengkap. Parameter format mengatur banyaknya data yang dikembalikan: 'full' menyertakan header dan isi, 'metadata' hanya mengembalikan header, sedangkan 'minimal' hanya mengembalikan ID dan label.
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])Mengekstrak Header Email
Header (From, To, Subject, Date) disimpan dalam message['payload']['headers'] sebagai daftar dict {'name': ..., 'value': ...}. Tulis fungsi pembantu untuk mengekstrak header berdasarkan namanya — Anda akan sangat sering menggunakannya.
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"]}')Mendekode Isi Email (base64)
Isi email dalam Gmail API dikodekan dengan base64url — varian base64 yang aman untuk URL, dengan + menjadi - dan / menjadi _. Gunakan base64.urlsafe_b64decode() untuk mendekode. Tangani email sederhana (satu bagian) maupun email multipart.
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))
Menangani Email Multipart Secara Rekursif
Email kompleks (dengan lampiran, gambar sebaris, atau konten campuran) merupakan struktur multipart bertingkat. Bagian isi dapat bertingkat hingga kedalaman berapa pun. Fungsi rekursif yang menelusuri pohon bagian dapat menangani semua kasus.
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])Menandai Pesan sebagai Telah Dibaca
Setelah memproses email, agen Anda sebaiknya menandainya sebagai telah dibaca dengan menghapus label UNREAD. Gunakan service.users().messages().modify() dengan removeLabelIds=['UNREAD']. Anda juga dapat menambahkan label seperti PROCESSED untuk melacak email yang telah ditangani agen.
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'))
Menyusun Email dengan MIMEText
Untuk mengirim email, susun terlebih dahulu sebagai pesan MIME menggunakan pustaka standar Python email. Kemudian, lakukan pengodean base64url pada byte mentahnya dan POST ke Gmail API. MIMEText menangani pengodean isi pesan dengan benar.
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']))
Mengirim Email dengan Gmail API
Kirim pesan yang telah disusun menggunakan service.users().messages().send(). Parameter userId='me' merujuk pada pengguna yang telah diautentikasi. API mengembalikan pesan terkirim beserta ID dan ID rangkaian percakapannya.
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)Membuat dan Mengirim Draf Email
Alih-alih langsung mengirim, agen dapat membuat draf untuk ditinjau manusia. Gunakan service.users().drafts().create(). Selanjutnya, manusia dapat meninjau dan mengirim draf tersebut dari antarmuka Gmail. Ini adalah pola yang direkomendasikan untuk email apa pun yang memerlukan persetujuan manusia.
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'])Memproses Banyak Email Secara Batch
Saat memproses banyak email, jangan mengambilnya satu per satu dalam perulangan yang rapat — Anda akan mencapai batas kuota. Gunakan perulangan terkendali dengan jeda singkat, atau fitur permintaan batch Gmail API untuk menggabungkan beberapa operasi dalam satu panggilan HTTP.
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 processedMembalas Email (Dalam Rangkaian Percakapan)
Untuk mengirim balasan dalam rangkaian percakapan, tetapkan header In-Reply-To dan References ke header Message-ID pesan asli, lalu teruskan threadId ke panggilan pengiriman. Dengan begitu, balasan tetap berada dalam rangkaian percakapan Gmail yang sama.
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
}Pemeriksaan Singkat: Isi Email base64
Uji pemahaman Anda tentang penanganan pesan Gmail API.
Ringkasan Membaca dan Mengirim Email
Sekarang agen Anda dapat membaca dan mengirim email secara terprogram:
- Membuat daftar:
messages().list(q='is:unread')mengembalikan ID; gunakan sintaks pencarian Gmail - Mengambil:
messages().get(id=..., format='full')mengembalikan pesan lengkap - Mengurai header: ekstrak From/Subject/Date dari
payload.headers - Mendekode isi:
base64.urlsafe_b64decode(data)untuk teks; telusuri bagian multipart secara rekursif - Mengirim: susun dengan
MIMEText, lakukan pengodean base64url, lalu POST melaluimessages().send() - Membalas dalam rangkaian percakapan: tetapkan header
In-Reply-To+threadIddalam isi pengiriman
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Membaca dan Mengirim Email Secara Terprogram” gratis?
Ya — teks lengkap “Membaca dan Mengirim Email Secara Terprogram” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Agents, upgrade ke CoddyKit PRO. Kursus AI Agents mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Membaca dan Mengirim Email Secara Terprogram”?
Mencantumkan pesan, mengambil isi pesan, dan mengirim email MIME. Kamu berlatih AI Agents dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai AI Agents?
Tidak diperlukan pengalaman sebelumnya. AI Agents di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Membaca dan Mengirim Email Secara Terprogram” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Agents ini?
Ya. Setiap pelajaran AI Agents menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Menghubungkan ke Gmail melalui API
- Membaca dan Mengirim Email Secara Terprogram
- Membuat dan Menanyakan Acara Kalender
- Membangun Agen Asisten Email Sederhana