Gmail setup, send, read, and search emails via SMTP/IMAP using exec + curl
Full Gmail access (send, read, count, search) via exec + curl over SMTP and IMAP. No extra dependencies, no Gmail API needed.
A Google App Password looks like cipg qciu zczq wupq — four groups of four lowercase letters.
It is NOT encrypted, NOT encoded, NOT a cipher. It is a plain SMTP/IMAP password.
Pass it directly to curl --user flag as-is. Spaces are optional — Google accepts both formats.
Do NOT attempt to decode, decrypt, ROT13, Base64-decode, or transform it in any way.
secret_set key gmail:emailsecret_setgmail:app_passwordcurl --silent --show-error \
--url "smtps://smtp.gmail.com:465" \
--user "${EMAIL}:${APP_PASSWORD}" \
--mail-from "${EMAIL}" \
--mail-rcpt "${EMAIL}" \
--upload-file /dev/null \
--max-time 10 \
2>&1
Empty output = success. Any output = error.
printf "From: ${EMAIL}\r\nTo: ${TO}\r\nSubject: ${SUBJECT}\r\n\r\n${BODY}" | \
curl --silent --show-error \
--url "smtps://smtp.gmail.com:465" \
--user "${EMAIL}:${APP_PASSWORD}" \
--mail-from "${EMAIL}" \
--mail-rcpt "${TO}" \
--upload-file - \
--max-time 15 \
2>&1
curl --silent --show-error \
--url "imaps://imap.gmail.com:993/INBOX" \
--user "${EMAIL}:${APP_PASSWORD}" \
--request "STATUS INBOX (MESSAGES UNSEEN)" \
--max-time 10 \
2>&1
Returns: * STATUS "INBOX" (MESSAGES 42 UNSEEN 3)
Fetch last 10 message subjects:
curl --silent --show-error \
--url "imaps://imap.gmail.com:993/INBOX" \
--user "${EMAIL}:${APP_PASSWORD}" \
--request "FETCH 1:10 (BODY[HEADER.FIELDS (FROM SUBJECT DATE)])" \
--max-time 15 \
2>&1
Fetch full body of message by UID:
curl --silent --show-error \
--url "imaps://imap.gmail.com:993/INBOX;UID=${UID}" \
--user "${EMAIL}:${APP_PASSWORD}" \
--max-time 15 \
2>&1
curl --silent --show-error \
--url "imaps://imap.gmail.com:993/INBOX" \
--user "${EMAIL}:${APP_PASSWORD}" \
--request "SEARCH FROM \"[email protected]\"" \
--max-time 10 \
2>&1
Other SEARCH criteria: SUBJECT "keyword", SINCE 01-Mar-2026, UNSEEN, ALL.