การอ่านและส่งอีเมลด้วยโปรแกรม
แสดงรายการข้อความ ดึงเนื้อหาข้อความ และส่งอีเมล MIME
การอ่านและส่งอีเมลด้วยโปรแกรม เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
การแสดงรายการข้อความด้วย Gmail API
ขั้นตอนแรกของการอ่านอีเมลคือการแสดงรายการข้อความที่ตรงตามเกณฑ์ของคุณ service.users().messages().list() จะคืนค่ารหัสข้อความและรหัสเธรด ไม่ใช่เนื้อหาทั้งหมด จากนั้นคุณจึงเรียกดูข้อความแต่ละรายการแยกกัน รูปแบบสองขั้นตอนนี้ช่วยให้การเรียกแสดงรายการทำงานได้รวดเร็ว
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')การดึงข้อความฉบับเต็ม
ใช้ service.users().messages().get() เพื่อดึงเนื้อหาข้อความฉบับเต็ม พารามิเตอร์ format จะควบคุมปริมาณข้อมูลที่ส่งกลับมา โดย 'full' จะรวมส่วนหัวและเนื้อหา 'metadata' จะส่งกลับเฉพาะส่วนหัว และ 'minimal' จะส่งกลับเฉพาะรหัสกับป้ายกำกับ
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])การดึงส่วนหัวของอีเมล
ส่วนหัว (ผู้ส่ง ผู้รับ หัวเรื่อง วันที่) ถูกจัดเก็บใน message['payload']['headers'] เป็นรายการดิกชันนารีรูปแบบ {'name': ..., 'value': ...} โปรดเขียนตัวช่วยเพื่อดึงส่วนหัวตามชื่อ เพราะคุณจะใช้ตัวช่วยนี้อยู่เสมอ
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"]}')การถอดรหัสเนื้อหาอีเมล (base64)
เนื้อหาอีเมลใน Gmail API จะถูกเข้ารหัสแบบ base64url ซึ่งเป็นรูปแบบของ base64 ที่ปลอดภัยสำหรับ URL โดย + จะกลายเป็น - และ / จะกลายเป็น _ ใช้ base64.urlsafe_b64decode() เพื่อถอดรหัส และรองรับทั้งอีเมลแบบง่าย (ส่วนเดียว) และอีเมลแบบหลายส่วน
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))
การจัดการอีเมลแบบหลายส่วนด้วยการเรียกซ้ำ
อีเมลที่ซับซ้อนซึ่งมีไฟล์แนบ รูปภาพแบบแทรกในเนื้อหา หรือเนื้อหาผสม จะมีโครงสร้างแบบหลายส่วนซ้อนกัน ส่วนต่าง ๆ ของเนื้อหาอาจซ้อนลึกได้โดยไม่มีข้อจำกัด ฟังก์ชันแบบเรียกซ้ำที่เดินสำรวจต้นไม้ของส่วนต่าง ๆ จะจัดการได้ทุกกรณี
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])การทำเครื่องหมายข้อความว่าอ่านแล้ว
หลังจากประมวลผลอีเมลแล้ว เอเจนต์ควรทำเครื่องหมายว่าอ่านแล้วด้วยการนำป้ายกำกับ UNREAD ออก ใช้ service.users().messages().modify() พร้อมกับ removeLabelIds=['UNREAD'] นอกจากนี้ยังเพิ่มป้ายกำกับอย่าง PROCESSED เพื่อติดตามอีเมลที่เอเจนต์จัดการแล้วได้
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'))
การเขียนอีเมลด้วย MIMEText
หากต้องการส่งอีเมล ขั้นแรกให้เขียนอีเมลเป็นข้อความ MIME โดยใช้ไลบรารีมาตรฐาน email ของ Python จากนั้นเข้ารหัสไบต์ดิบเป็น base64url และส่งด้วย POST ไปยัง Gmail API MIMEText จะจัดการการเข้ารหัสเนื้อหาข้อความอย่างถูกต้อง
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']))
การส่งอีเมลด้วย Gmail API
ส่งข้อความที่เขียนไว้ด้วย service.users().messages().send() พารามิเตอร์ userId='me' หมายถึงผู้ใช้ที่ยืนยันตัวตนแล้ว API จะคืนค่าข้อความที่ส่ง พร้อมรหัสข้อความและรหัสเธรด
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)การสร้างและส่งอีเมลฉบับร่าง
แทนที่จะส่งทันที เอเจนต์สามารถสร้างฉบับร่างให้มนุษย์ตรวจสอบได้ ใช้ service.users().drafts().create() จากนั้นมนุษย์สามารถตรวจสอบและส่งฉบับร่างผ่านส่วนติดต่อผู้ใช้ของ Gmail วิธีนี้เป็นรูปแบบที่แนะนำสำหรับอีเมลทุกฉบับที่ต้องได้รับการอนุมัติจากมนุษย์
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'])การประมวลผลอีเมลหลายฉบับเป็นกลุ่ม
เมื่อประมวลผลอีเมลจำนวนมาก อย่าดึงข้อมูลทีละฉบับในลูปที่ถี่เกินไป เพราะจะทำให้ถึงขีดจำกัดโควตา ใช้ลูปที่ควบคุมจังหวะและมีการหน่วงเวลาเล็กน้อย หรือใช้ความสามารถในการส่งคำขอแบบกลุ่มของ Gmail API เพื่อรวมการดำเนินการหลายรายการไว้ในการเรียก 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 processedการตอบกลับอีเมล (ภายในเธรด)
หากต้องการส่งการตอบกลับภายในเธรด ให้ตั้งค่าส่วนหัว In-Reply-To และ References เป็นค่าส่วนหัว Message-ID ของข้อความต้นฉบับ และส่ง threadId ไปกับการเรียกส่ง วิธีนี้จะทำให้การตอบกลับอยู่ในเธรดการสนทนาเดียวกันของ Gmail
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
}แบบทดสอบสั้น ๆ: เนื้อหาอีเมลแบบ base64
ทดสอบความเข้าใจเกี่ยวกับการจัดการข้อความของ Gmail API
สรุปการอ่านและส่งอีเมล
ขณะนี้เอเจนต์ของคุณสามารถอ่านและส่งอีเมลผ่านโปรแกรมได้แล้ว:
- แสดงรายการ:
messages().list(q='is:unread')จะคืนค่ารหัสข้อความ ให้ใช้ไวยากรณ์การค้นหาของ Gmail - ดึงข้อมูล:
messages().get(id=..., format='full')จะคืนค่าข้อความฉบับเต็ม - แยกส่วนหัว: ดึงผู้ส่ง/หัวเรื่อง/วันที่จาก
payload.headers - ถอดรหัสเนื้อหา: ใช้
base64.urlsafe_b64decode(data)สำหรับข้อความ และเรียกซ้ำในส่วนต่าง ๆ ของอีเมลแบบหลายส่วน - ส่ง: เขียนด้วย
MIMETextเข้ารหัสเป็น base64url แล้วส่งด้วย POST ผ่านmessages().send() - ตอบกลับในเธรด: ตั้งค่าส่วนหัว
In-Reply-Toและเพิ่มthreadIdในเนื้อหาการส่ง
คำถามที่พบบ่อย
บทเรียน “การอ่านและส่งอีเมลด้วยโปรแกรม” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การอ่านและส่งอีเมลด้วยโปรแกรม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การอ่านและส่งอีเมลด้วยโปรแกรม”
แสดงรายการข้อความ ดึงเนื้อหาข้อความ และส่งอีเมล MIME คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การอ่านและส่งอีเมลด้วยโปรแกรม” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม
ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเชื่อมต่อ Gmail ผ่าน API
- การอ่านและส่งอีเมลด้วยโปรแกรม
- การสร้างและค้นหาเหตุการณ์ในปฏิทิน
- การสร้างตัวแทนผู้ช่วยอีเมลอย่างง่าย