Send email with curl over SMTP from a shell script
One-liner and scripted examples of sending mail with curl's SMTP support: STARTTLS on 587 (--ssl-reqd), authentication, a message file with headers, and the msmtp alternative for cron jobs.
Install
shell
# curl is already installed; alternative: sudo apt install msmtp
Complete example
curl / Bash — STARTTLS on 587, credentials from the environment
# message.txt From: Your App <hello@yourdomain.com> To: customer@example.com Subject: Backup finished The nightly backup completed at $(date). # send (STARTTLS on 587) curl --ssl-reqd --url "smtp://smtp.queensmtp.com:587" \ --user "$SMTP_USER:$SMTP_PASS" \ --mail-from "hello@yourdomain.com" \ --mail-rcpt "customer@example.com" \ --upload-file message.txt # implicit TLS on 465 curl --url "smtps://smtp.queensmtp.com:465" --user "$SMTP_USER:$SMTP_PASS" \ --mail-from hello@yourdomain.com --mail-rcpt customer@example.com --upload-file message.txt # msmtp for cron/mail(1) users — ~/.msmtprc (chmod 600) defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt account default host smtp.queensmtp.com port 587 user your-smtp-username password your-smtp-password from hello@yourdomain.com # then: echo "body" | msmtp -s "subject" customer@example.com
What to know
- --ssl-reqd forces STARTTLS and fails rather than sending plaintext; smtps:// on 465 is implicit TLS.
- The uploaded file must contain the headers (From/To/Subject) and a blank line before the body — curl sends it verbatim.
- Add -v to see the SMTP conversation and the exact reply code when something fails.
Same code, different provider
Only the host, port and credentials change. The rules per provider are on the SMTP settings hub.
| Provider | Host | Port | Username | Password | Note |
|---|---|---|---|---|---|
| QueenSMTP | smtp.queensmtp.com | 587 (STARTTLS) / 465 (SSL) / 2525 | SMTP username from the dashboard | SMTP password | $5/year + $0.10 per 1,000; 100 free/day |
| Gmail | smtp.gmail.com | 587 / 465 | you@gmail.com | App Password | 500/day, From must be the account |
| Amazon SES | email-smtp.<region>.amazonaws.com | 587 / 465 / 2587 | SES SMTP username | SES SMTP password | sandbox 200/day until approved |
| Office 365 | smtp.office365.com | 587 | user@yourdomain.com | mailbox password | SMTP AUTH must be enabled; 30/min |
| SendGrid | smtp.sendgrid.net | 587 / 465 / 2525 | apikey | API key | no free plan since 2025 |
Credentials for the example above
Create a free account, verify your sending domain (SPF + DKIM shown in the dashboard), add an SMTP credential, and paste it into the code. 100 emails a day free; $5/year plus $0.10 per 1,000 after that. Prefer HTTPS? The same account has a REST email API.
Get SMTP credentials Test your settings firstOther languages and frameworks
PHPsend email over SMTP
Laravelsend email over SMTP
WordPresssend email over SMTP
Pythonsend email over SMTP
Djangosend email over SMTP
Flasksend email over SMTP
Node.jssend email over SMTP
Next.jssend email over SMTP
Javasend email over SMTP
C# / .NETsend email over SMTP
Gosend email over SMTP
Ruby on Railssend email over SMTP
Postfix (Linux relayhost)send email over SMTP
curl / Bash SMTP — questions
Authentication failed — wrong user/password for this host, or you connected on 25 where the server does not offer AUTH.
Related Guides
Continue learning with these related articles