Skip to content

A simple SMTP client library built in C++ that support authentication and secure connections (Forced SSL and Opportunistic SSL/TLS encryption)

License

Notifications You must be signed in to change notification settings

jeremydumais/CPP-SMTPClient-library

Repository files navigation

Jed# C++ SMTP Client Library

Latest version Dependencies Conan Center language OS

⭐ Star us on GitHub β€” it motivates us a lot!

A simple SMTP client library built in C++ that support authentication and secure connections (Opportunistic SSL/TLS and Forced SSL encryption).

For TLS 1.3 support you must build the library against OpenSSL 1.1.1
The library is cross-platform and has been tested on Linux, Windows and macOS.

πŸ› οΈ How to build the SMTP client library

πŸ‘‰ Refer to this guide for instructions on building the library.
πŸ‘‰ Refer to this guide for instructions on consuming the library in your own applications.

Follow these guides for platform-specific instructions: Windows , Linux and macOS.

πŸ“₯ Download latest binaries

Windows

Release MD5 hash of smtpclient.dll

v1.1.12 (x64)

fc7613b5d30ff094bd8649dd9707cc02

v1.1.11 (x64)

908ec5889757fb4a5874d99d9f6311ee

v1.1.10 (x64)

1a82a5e48b959dfd359860a86df0df66

See the section Releases for previous versions.

πŸ“° What's new

  • Version 1.1.12:
    • The default --sep Multipart encapsulation boundary is now a randomly generated string to ensure that it doesn't conflict if the --sep string appears in the email body. See RFC 1341 section 7.2.1. This change has been made by ino-josh. Many thanks!
    • Fix CMake install paths to prevent build path leakage in generated config files. If using default build values, the library out file will not appears in a smtpclient folder, but one level above. This change has been made by ino-josh. Many thanks!
    • Add a Message-ID generated header when sending a message. See RFC 5322 section 3.6.4. Thanks to PowerTAMX for reporthing this.
  • Version 1.1.11:
    • Fix the error 554 5.0.0 ("failed to create parser: unexpected EOF") when sending multipart messages via ProtonMail Bridge due to missing closing MIME boundary (--sep--).
    • Prevented catastrophic backtracking in isEmailAddressValid() regex that caused crashes when validating complex email addresses (e.g., from mailersend.com). Updated regex to avoid unescaped dots and added a more robust pattern.
    • Adjust the line length of the MIME attachments to 76 (excluding CRLF) to comply with RFC 2045.
    • Add a log level to the multiple clients. The log level is for the level of details of the communication log between the client and the server. Choices are : None, ExcludeAttachmentsBytes and Full. Default is ExcludeAttachmentsBytes.
    • Add the Date header field in outgoing emails to comply with RFC 2822. This is a required field and it was missing in the previous versions.
  • Version 1.1.10:
    • Solve the issue where STARTTLS is not recognized if it is returned as the last response from the mail server.
    • Add support for macOS.
    • Fix the install/uninstall process of the library.

⚑️ Quickstart - The 3 client classes

OpportunisticSecureSMTPClient

The OpportunisticSecureSMTPClient should be your default choice for communicating with modern SMTP servers. The communication is usually done via port 587.

In this mode, the communication starts unencrypted, then the client will asked the server to provide the supported options and if the server supports encryption, the STARTTLS command will be sent. Negotiation will take place between the server and the client to find the most secure encryption to use for communication.

If the server does not support encryption, the communication will remain unencrypted and it will be logged in the communication log.

This client can be used for newest SMTP servers like Google Gmail, Microsoft Office 365 or good old uncrypted SMTP servers.

ForcedSecureSMTPClient

The ForcedSecureSMTPClient is useful to communicate with legacy systems which requires that the communication be encrypted from the initial connection. The communication is usually done via port 465.

SmtpClient

The SmtpClient should be used to communicate with internal relay servers. It does not support encryption of communications. The communication is usually done via port 25.

βš™ How it works

2-ways of consuming the library

From in version 1.1.5+

You can consume objects in the library either using the C++ Interface (the jed_utils::cpp namespace) or using the Pure C Interface (the jed_utils namespace).

The Pure C Interface was designed primarily to maintain binary compatibility between major versions of the MSVC compiler toolsets. C++ binary compatibility between Visual Studio versions

To see some usage examples with Pure C Interface refer to the wiki Some examples with Pure C Interface

This problem has been resolved since 2015 so it is no longer an issue.

The C++ Interface should then be your default choice.

Some examples with C++ Interface

From in version 1.1.5+

From in version 1.1.6+

Send a plaintext email via a secure server (opportunistic)

#include "cpp/opportunisticsecuresmtpclient.hpp"
#include "cpp/plaintextmessage.hpp"
#include <iostream>
#include <stdexcept>

using namespace jed_utils::cpp;

int main() {
	OpportunisticSecureSMTPClient client("<your smtp server address>", 587);
	client.setCredentials(Credential("[email protected]", "mypassword"));
	try	{
		PlaintextMessage msg(MessageAddress("[email protected]", "Test Address Display"),
			{ MessageAddress("[email protected]", "Another Address display") },
			"This is a test (Subject)",
			"Hello\nHow are you?");

		int err_no = client.sendMail(msg);
		if (err_no != 0) {
			std::cerr << client.getCommunicationLog() << '\n';
			std::string errorMessage = client.getErrorMessage(err_no);
			std::cerr << "An error occurred: " << errorMessage
                 << " (error no: " << err_no << ")" << '\n';
			return 1;
		}
		std::cout << client.getCommunicationLog() << '\n';
		std::cout << "Operation completed!" << std::endl;
	}
	catch (std::invalid_argument &err) {
		std::cerr << err.what() << std::endl;
	}
    return 0;
}

Send an html email to 2 recipients with an attachment via a secured server (opportunistic)

You will need to include cpp/htmlmessage.hpp

OpportunisticSecureSMTPClient client("<your smtp server address>", 587);
client.setCredentials(Credential("[email protected]", "mypassword"));

const MessageAddress from("[email protected]", "Test Address Display");
const auto to = { MessageAddress("[email protected]") };
const auto subject = "This is a test (Subject)";
const auto body = "<html><body><h1>Hello,</h1><br/><br/>How are you?</body></html>";
const auto cc = { MessageAddress("[email protected]") };
const std::vector<MessageAddress> bcc = {};
const auto attachment = { Attachment("C:\\Temp\\test.png", "test image.png") };
HTMLMessage msg(from, to, subject, body, cc, bcc, attachment);

client.sendMail(msg);

Send a plaintext email via a secure server (forced)

You will need to include cpp/forcedsecuresmtpclient.hpp

ForcedSecureSMTPClient client("<your smtp server address>", 465);
client.setCredentials(Credential("[email protected]", "mypassword"));

PlaintextMessage msg(MessageAddress("[email protected]", "Test Address Display"),
    { MessageAddress("[email protected]", "Another Address display") },
    "This is a test (Subject)",
    "Hello\nHow are you?");

client.sendMail(msg);
}

Send an html email with an attachment using Content-ID via a secured server (opportunistic)

You will need to include cpp/htmlmessage.hpp

OpportunisticSecureSMTPClient client("<your smtp server address>", 587);
client.setCredentials(Credential("[email protected]", "mypassword"));

const MessageAddress from("[email protected]", "Test Address Display");
const auto to = { MessageAddress("[email protected]") };
const auto subject = "This is a test (Subject)";
const auto body = "<html><body><img src='cid:[email protected]' /></body></html>";
const auto cc = { MessageAddress("[email protected]") };
const std::vector<MessageAddress> bcc = {};
const auto attachment = { Attachment("C:\\Temp\\test.png", "test image.png", "[email protected]") };
HTMLMessage msg(from, to, subject, body, cc, bcc, attachment);

client.sendMail(msg);

Complete communication log

The library keeps each exchange between the client and the server in the communication log for easy diagnosis in the event of a communication problem.

Here's is an example communication log of a successful email send :

c: Trying to connect to smtp.gmail.com on port 587
s: 220 smtp.gmail.com ESMTP v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
c: Connected!
c: ehlo localhost\r\n
s: 250-smtp.gmail.com at your service, [129.222.207.110]
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
c: Info: STARTTLS is available by the server, the communication will be encrypted.
c: STARTTLS\r\n
s: 220 2.0.0 Ready to start TLS
c: <Start TLS negotiation>
c & s: <Negotiate a TLS session>
c & s: <Check result of negotiation>
c: TLS session ready!
c: Contacting the server again but via the secure channel...
c: ehlo localhost\r\n
s: 250-smtp.gmail.com at your service, [129.222.207.110]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
c: AUTH PLAIN ***************\r\n
s: 235 2.7.0 Accepted
c: MAIL FROM: <Test Address Display [email protected]>\r\n
s: 250 2.1.0 OK v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
c: RCPT TO: <youremailaddress@localhost>\r\n
s: 250 2.1.5 OK v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
c: DATA\r\n
s: 354  Go ahead v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
c: Date: Wed, 23 Jul 2025 06:46:47 -0500\r\n
c: Message-ID: <[email protected]>\r\n
c: From: [email protected]\r\n
c: To: youremailaddress@localhost\r\n
c: Subject: This is a test (Subject)\r\n
c: Content-Type: multipart/mixed; boundary=sep\r\n\r\n
c: --sep\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><body><p>Body sample</p></body></html>\r\n
c: \r\n.\r\n
s: 250 2.0.0 OK  1672495787 v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
c: QUIT\r\n
Operation completed!

πŸ— Complete XOAUTH2 authentication example

We also provide a fully working example. See send-mail.cpp. Make sure you replace the username and password (access token) placeholders with correct values.

The example uses GMail smtp server with XOauth2 authentication mechanism.

For testing purposes, you can obtain an OAuth access token for you gmail account by using the OAuth 2.0 Playground. You can follow this procedure for more details: Obtaining an access token for your gmail account

πŸ§ͺ Unit tests

How to run the unit tests

πŸ“š Documentation

See the classes documentation here

βš–οΈ License

See LICENSE

About

A simple SMTP client library built in C++ that support authentication and secure connections (Forced SSL and Opportunistic SSL/TLS encryption)

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 5