What are the Curl SMTP command line arguments to support GMail TLS/STARTTLS vs SSL
Stefan Bogdanescu
Founder & Senior Architect
Mastering SMTP via Curl: Understanding TLS/STARTTLS vs. SSL Negotiation for Email Delivery
As developers building applications that require external service interaction—especially when dealing with sensitive protocols like email delivery—using command-line tools like curl is incredibly useful for testing connectivity and authentication flows. When sending emails via SMTP, the choice between port 587 (STARTTLS) and port 465 (SSL/SMTPS) dictates how the underlying security handshake occurs. Misunderstanding these differences often leads to connection failures, even when credentials are correct.
This post will dive deep into the nuances of using curl for SMTP communication, explaining precisely which command-line arguments are required to successfully negotiate TLS/STARTTLS versus implicit SSL connections to major email providers like Gmail.
The SMTP Protocol: Port Differences Explained
The core issue lies in how these two ports handle the security layer negotiation:
- Port 587 (TLS/STARTTLS): This port is the modern standard for secure SMTP. The connection is established over plain TCP, and immediately after the initial connection, the client issues the
STARTTLScommand to upgrade the connection to a secure TLS session. This requires explicit negotiation. - Port 465 (SSL/SMTPS): This port mandates that the connection itself is encrypted using SSL/TLS from the very beginning of the handshake. The encryption is implicit in the port choice, meaning no separate
STARTTLScommand is required; the secure tunnel is established immediately upon connection.
When using curl, the flags you employ must correctly signal to the server which security context you intend to use.
Correcting the curl Command for Each Protocol
The previous attempts often failed because the --ssl flag in curl sometimes applies globally or conflicts with the specific protocol handshake required by the SMTP client. We need to focus on ensuring the connection type is correctly signaled alongside authentication details.
Scenario 1: Explicit TLS (STARTTLS on Port 587)
For STARTTLS, you need a standard secure connection followed by the protocol command. The --ssl flag generally initiates the necessary TLS negotiation for this port.
Correct Command Structure for Port 587:
curl smtp://smtp.gmail.com:587 -v \
--mail-from "my.mail@gmail.com" \
--mail-rcpt "your.mail@x.com" \
--ssl \
-u my.mail@gmail.com:password \
-T "c:\test.txt" -k --anyauth
In this setup, --ssl explicitly tells curl to use the TLS protocol over the established connection on port 587, which aligns perfectly with the STARTTLS requirement for many modern mail servers.
Scenario 2: Implicit SSL (SSL on Port 465)
For implicit SSL connections used on port 465, forcing an additional --ssl flag can introduce conflict. When using port 465, the encryption is expected by default. The key is often to rely on the port itself and ensure you are only specifying necessary authentication parameters.
Correct Command Structure for Port 465:
curl smtp://smtp.gmail.com:465 -v \
--mail-from "my.mail@gmail.com" \
--mail-rcpt "your.mail@x.com" \
-u my.mail@gmail.com:password \
-T "c:\test.txt" -k --anyauth
Notice the removal of the redundant --ssl flag when using port 465. By specifying :465, you are instructing curl to connect to that specific encrypted port, which implicitly handles the required SSL handshake without needing the extra flag. This approach mirrors how secure API interactions—like those often seen when building services on platforms like Laravel—handle mandatory security layers by relying on correct endpoint definitions.
Best Practices and Conclusion
When dealing with network protocols via command-line tools, always treat the port number and the flags as defining a specific state. For email delivery testing using curl, explicitly matching the port to the protocol expectation (587 for STARTTLS, 465 for SSL) and carefully applying security flags is essential.
Always prioritize debugging by isolating variables: test Port 587 with --ssl and Port 465 without it. If you are building robust systems that rely on external services—much like how modern backend frameworks manage secure API calls within the Laravel ecosystem—this meticulous attention to network configuration prevents obscure connection errors down the line. By understanding these fundamental networking concepts, you move from simply running commands to truly mastering secure service interaction.
Note: Blog content is currently available in English.