GWS CLI 지메일

메일 자동화에서 중요한 것은 발송까지 간다는 점입니다. 초안만 만들어놓고 사람에게 “보내기를 눌러주세요”라고 하는 도구는 일을 끝내지 못합니다.

기본기와 인증은 GWS CLI에 있습니다.


1. 받은편지함 훑기 — +triage

gws gmail +triage                                  # 안 읽은 메일 20통(기본)
gws gmail +triage --max 5 --query 'from:boss'
gws gmail +triage --labels                         # 라벨 이름까지
gws gmail +triage --format json | jq '.[].subject'

읽기 전용입니다. 받은편지함을 건드리지 않습니다. 기본 질의는 is:unread이고 --query에 지메일 검색 문법을 그대로 쓸 수 있습니다. 기본 출력이 표라서 사람이 보기 편합니다.

자주 쓰는 질의:

목적질의
특정 발신자from:[email protected]
기간after:2026/10/01 before:2026/10/09
첨부 있는 것has:attachment
제목subject:견적
라벨label:중요
안 읽은 받은편지함is:unread in:inbox

2. 한 통 읽기 — +read

gws gmail +read --id <메시지ID>
gws gmail +read --id <메시지ID> --headers          # From·To·Subject·Date 포함
gws gmail +read --id <메시지ID> --format json | jq -r '.body'
gws gmail +read --id <메시지ID> --html             # HTML 본문 그대로

multipart/alternative 구조와 base64 디코딩을 알아서 처리하고, HTML만 있는 메일은 평문으로 바꿔 줍니다. 원시 API로 직접 파싱하면 이 세 가지에서 다 걸립니다.

메시지 ID는 +triage 출력의 id 칸에 있습니다.

3. 보내기 — +send

gws gmail +send --to [email protected] --subject '제목' --body '본문'

이 한 줄이 RFC 5322 형식·MIME 인코딩·base64를 전부 처리합니다. 한글 제목도 그냥 넣으면 됩니다.

옵션쓰임
--cc --bcc쉼표로 여럿
--html--body를 HTML로 해석
-a <파일>첨부(여러 번 반복 가능)
--from <주소>별칭·send-as 주소로 보내기
--draft보내지 않고 임시보관함에 저장
--dry-run보내지 않고 조립된 요청만 보여주기
gws gmail +send --to [email protected] --cc [email protected] \
  --subject '10월 보고' --body '첨부 확인 부탁드립니다.' \
  -a 보고서.pdf -a 부록.csv

🔴 발송 전에 --dry-run을 한 번 돌리십시오. 메일은 되돌릴 수 없습니다. 받는 사람·제목·첨부가 맞는지 보고 나서 플래그를 떼십시오.

수동으로 MIME을 조립하던 옛 방식

원시 API로도 보낼 수 있습니다. 파이썬으로 본문을 만들어 base64url로 인코딩해 raw에 넣는 방식입니다.

RAW=$(python3 -c "
import base64
msg='To: [email protected]\r\nSubject: 제목\r\n\r\n본문\r\n'
print(base64.urlsafe_b64encode(msg.encode()).decode())")
gws gmail users messages send --params '{"userId":"me"}' --json "{\"raw\":\"$RAW\"}"

이제 이렇게 할 이유가 없습니다. +send가 같은 일을 하면서 한글 인코딩·첨부·스레드 처리까지 맡습니다. 이 방식은 헤더를 직접 손봐야 하는 특수한 경우에만 남겨두십시오.

4. 답장·전달

# 답장 — 스레드 처리 자동
gws gmail +reply --message-id <ID> --body '확인했습니다.'
gws gmail +reply --message-id <ID> --body '캐롤 참조 넣습니다' --cc [email protected]
gws gmail +reply --message-id <ID> --body '수정본 보냅니다' -a 수정본.docx
 
# 전원 답장
gws gmail +reply-all --message-id <ID> --body '모두 확인 부탁드립니다.'
 
# 전달
gws gmail +forward --message-id <ID> --to [email protected] --body '참고하십시오'
gws gmail +forward --message-id <ID> --to [email protected] --no-original-attachments

+reply는 In-Reply-To·References·threadId를 자동으로 채우고 원문을 인용해 붙입니다. 스레드가 끊겨 따로 뜨는 사고가 여기서 사라집니다. --draft와 --dry-run도 같이 씁니다.

5. 새 메일 감시 — +watch

gws gmail +watch --project <GCP프로젝트> --label-ids INBOX --once
gws gmail +watch --project <GCP프로젝트> --cleanup --output-dir ./emails

새 메일을 NDJSON으로 흘려보냅니다. 뒤에서 Pub/Sub 토픽·구독을 만들어 쓰기 때문에 GCP 프로젝트가 필요합니다.

  • 지메일 watch는 7일 뒤 만료됩니다. 계속 쓰려면 다시 걸어야 합니다.
  • --cleanup 없이 끝내면 Pub/Sub 자원이 남습니다. 재접속할 거면 남기고, 아니면 붙이십시오.
  • 🔴 알림을 받아 다시 쏘는 구조를 만들 거면 억제·묶음 발송을 처음부터 넣으십시오. 안 넣으면 받은편지함이 자기 알림으로 덮입니다.

6. 원시 API가 필요한 일

라벨 조작, 스팸·휴지통 이동, 필터는 헬퍼에 없습니다.

gws gmail users labels list --params '{"userId":"me"}'
gws gmail users messages modify --params '{"userId":"me","id":"<ID>"}' \
  --json '{"addLabelIds":["<라벨ID>"],"removeLabelIds":["UNREAD"]}'
gws gmail users messages list --params '{"userId":"me","q":"older_than:1y","maxResults":100}'
gws gmail users drafts list --params '{"userId":"me"}'
gws gmail users settings sendAs list --params '{"userId":"me"}'

userId는 자기 계정이면 항상 "me"입니다.

7. 스코프

발송에는 gmail.send·gmail.compose·gmail.modify·mail.google.com 중 하나면 됩니다. 읽기·라벨 조작까지 하려면 gmail.modify가 무난합니다. 처음 로그인할 때 필요한 범위를 한 번에 받아두십시오 — 나중에 스코프를 늘리려면 동의 흐름을 다시 타야 합니다.

8. 함께 읽기