Skip to content

Commit 1d38358

Browse files
authored
Merge pull request #50 from jeremydumais/version1.1.12
Version 1.1.12
2 parents 9ddedf7 + e3f8fe5 commit 1d38358

15 files changed

+461
-76
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22

33
All notable changes to this project will be documented in this file
44

5+
## [1.1.12]
6+
7+
### Enhancement
8+
- The default --sep Multipart encapsulation boundary is now a randomly generated
9+
string to ensure that it doesn't conflict if the --sep string appears in the
10+
email body.
11+
See [RFC 1341 section 7.2.1](https://datatracker.ietf.org/doc/html/rfc1341#page-30).
12+
This change has been made by [ino-josh](https://github.com/ino-josh).
13+
Many thanks!
14+
- Fix CMake install paths to prevent build path leakage in generated config
15+
files. If using default build values, the library out file will not appears in
16+
a smtpclient folder, but one level above.
17+
This change has been made by [ino-josh](https://github.com/ino-josh).
18+
Many thanks!
19+
- Add a Message-ID generated header when sending a message.
20+
See [RFC 5322 section 3.6.4](https://datatracker.ietf.org/doc/html/rfc5322).
21+
Thanks to [PowerTAMX](https://github.com/PowerTAMX) for reporthing this.
22+
523
## [1.1.11]
624

725
### Bug fixes

CMakeLists.txt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ set(PROJECT_SOURCE_FILES ${SRC_PATH}/attachment.cpp
105105
${SRC_PATH}/htmlmessage.cpp
106106
${SRC_PATH}/message.cpp
107107
${SRC_PATH}/messageaddress.cpp
108+
${SRC_PATH}/messageidutils.cpp
108109
${SRC_PATH}/plaintextmessage.cpp
109110
${SRC_PATH}/smtpclientbase.cpp
110111
${SRC_PATH}/smtpclient.cpp
@@ -183,9 +184,16 @@ else()
183184
add_library(${PROJECT_NAME}
184185
${PROJECT_SOURCE_FILES})
185186
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
186-
target_include_directories(${PROJECT_NAME} PUBLIC ${OPENSSL_INCLUDE_DIR})
187+
# Use install interface for include and lib dirs to avoid build path leakage
188+
target_include_directories(${PROJECT_NAME} PUBLIC
189+
$<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>
190+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
191+
)
187192
get_filename_component(ssl_libdir ${OPENSSL_SSL_LIBRARY} DIRECTORY)
188-
target_link_directories(${PROJECT_NAME} PUBLIC ${ssl_libdir})
193+
target_link_directories(${PROJECT_NAME} PUBLIC
194+
$<BUILD_INTERFACE:${ssl_libdir}>
195+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}>
196+
)
189197
target_link_libraries(${PROJECT_NAME} ssl crypto)
190198
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") #gcc
191199
# https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
@@ -264,6 +272,7 @@ if (BUILD_TESTING)
264272
add_executable(${PROJECT_UNITTEST_NAME} ${INCLUDE_PATH}
265273
${TEST_SRC_PATH}/main.cpp
266274
${TEST_SRC_PATH}/messageaddress_unittest.cpp
275+
${TEST_SRC_PATH}/messageidutils_unittest.cpp
267276
${TEST_SRC_PATH}/message_unittest.cpp
268277
${TEST_SRC_PATH}/message_cpp_unittest.cpp
269278
${TEST_SRC_PATH}/attachment_unittest.cpp
@@ -287,21 +296,21 @@ endif()
287296
# Install rules
288297
install(TARGETS smtpclient
289298
EXPORT smtpclientTargets
290-
LIBRARY DESTINATION lib/smtpclient
291-
ARCHIVE DESTINATION lib/smtpclient
292-
RUNTIME DESTINATION bin
293-
INCLUDES DESTINATION include
299+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
300+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
301+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
302+
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
294303
)
295304

296305
install(DIRECTORY ${SRC_PATH}/
297-
DESTINATION include/smtpclient
306+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/smtpclient
298307
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
299308
)
300309

301310
install(EXPORT smtpclientTargets
302311
FILE smtpclientTargets.cmake
303312
NAMESPACE smtpclient::
304-
DESTINATION lib/cmake/smtpclient
313+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/smtpclient
305314
)
306315

307316
include(CMakePackageConfigHelpers)
@@ -314,13 +323,13 @@ write_basic_package_version_file(
314323
configure_package_config_file(
315324
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/smtpclientConfig.cmake.in"
316325
"${CMAKE_CURRENT_BINARY_DIR}/smtpclientConfig.cmake"
317-
INSTALL_DESTINATION lib/cmake/smtpclient
326+
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/smtpclient
318327
)
319328

320329
install(FILES
321330
"${CMAKE_CURRENT_BINARY_DIR}/smtpclientConfig.cmake"
322331
"${CMAKE_CURRENT_BINARY_DIR}/smtpclientConfigVersion.cmake"
323-
DESTINATION lib/cmake/smtpclient
332+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/smtpclient
324333
)
325334

326335
# Uninstall target

CMakeLists.txt.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 2.8.2)
1+
cmake_minimum_required(VERSION 3.10)
22

33
project(googletest-download NONE)
44

README.md

Lines changed: 23 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Jed# C++ SMTP Client Library
22

3-
![Latest version](https://img.shields.io/badge/latest_version-1.1.11-brightgreen)
3+
![Latest version](https://img.shields.io/badge/latest_version-1.1.12-brightgreen)
44
![Dependencies](https://img.shields.io/badge/dependencies-openssl-brightgreen)
55
[![Conan Center](https://img.shields.io/conan/v/cpp-smtpclient-library)](https://conan.io/center/recipes/cpp-smtpclient-library)
66
[![language](https://img.shields.io/badge/language-c++-0078D4)](#)
@@ -31,80 +31,42 @@ Follow these guides for platform-specific instructions: [Windows](https://github
3131
<th> Release </th>
3232
<th> MD5 hash of smtpclient.dll </th>
3333
</tr>
34-
35-
<tr>
36-
<td>
37-
38-
[v1.1.11 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.11/CPP-SMTPClient-Library.1.1.11.x64.zip)
39-
40-
</td>
41-
<td>
42-
43-
908ec5889757fb4a5874d99d9f6311ee
44-
45-
</td>
46-
</tr>
4734

4835
<tr>
4936
<td>
5037

51-
[v1.1.10 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.10/CPP-SMTPClient-Library.1.1.10.x64.zip)
38+
[v1.1.12 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.12/CPP-SMTPClient-Library.1.1.12.x64.zip)
5239

5340
</td>
5441
<td>
5542

56-
1a82a5e48b959dfd359860a86df0df66
43+
fc7613b5d30ff094bd8649dd9707cc02
5744

5845
</td>
5946
</tr>
6047

6148
<tr>
6249
<td>
6350

64-
[v1.1.9 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.9/CPP-SMTPClient-Library.1.1.9.x64.zip)
65-
66-
</td>
67-
<td>
68-
69-
469dae64a844b8b193249bbbc280793e
70-
71-
</td>
72-
</tr>
73-
74-
<tr>
75-
<td>
76-
77-
[v1.1.8 (x86)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.9/CPP-SMTPClient-Library.1.1.9.x86.zip)
51+
[v1.1.11 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.11/CPP-SMTPClient-Library.1.1.11.x64.zip)
7852

7953
</td>
8054
<td>
8155

82-
940a0661eb0834b8966b1e92783ad181
56+
908ec5889757fb4a5874d99d9f6311ee
8357

8458
</td>
8559
</tr>
8660

8761
<tr>
8862
<td>
8963

90-
[v1.1.8 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.8/CPP-SMTPClient-Library.1.1.8.x64.zip)
91-
92-
</td>
93-
<td>
94-
95-
813e656a811af15891d4c1160a21dec9
96-
97-
</td>
98-
</tr>
99-
<tr>
100-
<td>
101-
102-
[v1.1.8 (x86)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.8/CPP-SMTPClient-Library.1.1.8.x86.zip)
64+
[v1.1.10 (x64)](https://github.com/jeremydumais/CPP-SMTPClient-library/releases/download/v1.1.10/CPP-SMTPClient-Library.1.1.10.x64.zip)
10365

10466
</td>
10567
<td>
10668

107-
277b9c257decc619a6358de58b213928
69+
1a82a5e48b959dfd359860a86df0df66
10870

10971
</td>
11072
</tr>
@@ -118,6 +80,21 @@ for previous versions.
11880
## 📰 What's new
11981

12082

83+
- Version 1.1.12:
84+
- The default --sep Multipart encapsulation boundary is now a randomly generated
85+
string to ensure that it doesn't conflict if the --sep string appears in the
86+
email body.
87+
See [RFC 1341 section 7.2.1](https://datatracker.ietf.org/doc/html/rfc1341#page-30).
88+
This change has been made by [ino-josh](https://github.com/ino-josh).
89+
Many thanks!
90+
- Fix CMake install paths to prevent build path leakage in generated config
91+
files. If using default build values, the library out file will not appears in
92+
a smtpclient folder, but one level above.
93+
This change has been made by [ino-josh](https://github.com/ino-josh).
94+
Many thanks!
95+
- Add a Message-ID generated header when sending a message.
96+
See [RFC 5322 section 3.6.4](https://datatracker.ietf.org/doc/html/rfc5322).
97+
Thanks to [PowerTAMX](https://github.com/PowerTAMX) for reporthing this.
12198
- Version 1.1.11:
12299
- Fix the error 554 5.0.0 ("failed to create parser: unexpected EOF") when
123100
sending multipart messages via ProtonMail Bridge due to missing closing MIME
@@ -139,18 +116,6 @@ for previous versions.
139116
last response from the mail server.
140117
- Add support for macOS.
141118
- Fix the install/uninstall process of the library.
142-
- Version 1.1.9:
143-
- Rework the build system to support static build and to generate correct
144-
release version.
145-
- The build configuration now works with multi-config generators like Visual
146-
Studio
147-
- The default build configurations in Visual Studio has been changed to :
148-
- x64-Debug
149-
- x64-Debug-Static
150-
- x64-Debug-WithUnitTests
151-
- x64-Release
152-
- x64-Release-Static
153-
- x64-Release-WithUnitTests
154119

155120
## ⚡️ Quickstart - The 3 client classes
156121

@@ -353,6 +318,7 @@ s: 250 2.1.5 OK v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
353318
c: DATA\r\n
354319
s: 354 Go ahead v2-20020a05620a440200b006fed2788751sm17411101qkp.76 - gsmtp
355320
c: Date: Wed, 23 Jul 2025 06:46:47 -0500\r\n
321+
c: Message-ID: <[email protected]>\r\n
356322
c: From: [email protected]\r\n
357323
c: To: youremailaddress@localhost\r\n
358324
c: Subject: This is a test (Subject)\r\n

src/cpp/messageaddress.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ std::string MessageAddress::getDisplayName() const {
2020
return jed_utils::MessageAddress::getDisplayName();
2121
}
2222

23+
std::string MessageAddress::getDomainName() const {
24+
return jed_utils::MessageAddress::getDomainName();
25+
}
26+
2327
jed_utils::MessageAddress MessageAddress::toStdMessageAddress() const {
2428
return jed_utils::MessageAddress(jed_utils::MessageAddress::getEmailAddress(),
2529
jed_utils::MessageAddress::getDisplayName());

src/cpp/messageaddress.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class CPP_MESSAGEADDRESS_API MessageAddress : private jed_utils::MessageAddress
6464
/** Return the display name. */
6565
std::string getDisplayName() const;
6666

67+
/** Return the domain name. */
68+
std::string getDomainName() const;
69+
6770
jed_utils::MessageAddress toStdMessageAddress() const;
6871

6972
friend class Message;

src/messageaddress.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "messageaddress.h"
22
#include <cstddef>
3+
#include <cstring>
34
#include <regex>
45
#include <stdexcept>
56
#include <string>
@@ -8,7 +9,7 @@
89
using namespace jed_utils;
910

1011
MessageAddress::MessageAddress(const char *pEmailAddress, const char *pDisplayName)
11-
: mEmailAddress(nullptr), mDisplayName(nullptr) {
12+
: mEmailAddress(nullptr), mDisplayName(nullptr), mDomainName(nullptr) {
1213
std::string email_address { pEmailAddress };
1314
// Check if the email address is not empty or white spaces
1415
if (email_address.length() == 0 || StringUtils::trim(email_address).empty()) {
@@ -28,30 +29,48 @@ MessageAddress::MessageAddress(const char *pEmailAddress, const char *pDisplayNa
2829
mDisplayName = new char[name_len+1];
2930
strncpy(mDisplayName, pDisplayName, name_len);
3031
mDisplayName[name_len] = '\0';
32+
33+
std::string emailAddress(mEmailAddress);
34+
auto atPos = emailAddress.find('@');
35+
if (atPos == std::string::npos || atPos == emailAddress.size() - 1) {
36+
mDomainName = new char[1];
37+
mDomainName[0] = '\0';
38+
} else {
39+
auto domainNamePart = emailAddress.substr(atPos + 1);
40+
mDomainName = new char[domainNamePart.length() +1];
41+
strncpy(mDomainName, domainNamePart.c_str(), domainNamePart.length());
42+
mDomainName[domainNamePart.length()] = '\0';
43+
}
3144
}
3245

3346
MessageAddress::~MessageAddress() {
3447
delete[] mEmailAddress;
3548
delete[] mDisplayName;
49+
delete[] mDomainName;
3650
}
3751

3852
// Copy constructor
3953
MessageAddress::MessageAddress(const MessageAddress& other)
4054
: mEmailAddress(new char[strlen(other.mEmailAddress) + 1]),
41-
mDisplayName(new char[strlen(other.mDisplayName) + 1]) {
55+
mDisplayName(new char[strlen(other.mDisplayName) + 1]),
56+
mDomainName(new char[strlen(other.mDomainName) + 1]) {
4257
size_t email_len = strlen(other.mEmailAddress);
4358
strncpy(mEmailAddress, other.mEmailAddress, email_len);
4459
mEmailAddress[email_len] = '\0';
4560
size_t name_len = strlen(other.mDisplayName);
4661
strncpy(mDisplayName, other.mDisplayName, name_len);
4762
mDisplayName[name_len] = '\0';
63+
size_t domain_len = strlen(other.mDomainName);
64+
strncpy(mDomainName, other.mDomainName, domain_len);
65+
mDomainName[domain_len] = '\0';
4866
}
4967

5068
// Assignment operator
5169
MessageAddress& MessageAddress::operator=(const MessageAddress& other) {
5270
if (this != &other) {
5371
delete[] mEmailAddress;
5472
delete[] mDisplayName;
73+
delete[] mDomainName;
5574
// mEmailAddress
5675
size_t email_len = strlen(other.mEmailAddress);
5776
mEmailAddress = new char[email_len + 1];
@@ -62,32 +81,42 @@ MessageAddress& MessageAddress::operator=(const MessageAddress& other) {
6281
mDisplayName = new char[name_len + 1];
6382
strncpy(mDisplayName, other.mDisplayName, name_len);
6483
mDisplayName[name_len] = '\0';
84+
// mDomainName
85+
size_t domain_len = strlen(other.mDomainName);
86+
mDomainName = new char[domain_len + 1];
87+
strncpy(mDomainName, other.mDomainName, domain_len);
88+
mDomainName[domain_len] = '\0';
6589
}
6690
return *this;
6791
}
6892

6993
// Move constructor
7094
MessageAddress::MessageAddress(MessageAddress&& other) noexcept
7195
: mEmailAddress(other.mEmailAddress),
72-
mDisplayName(other.mDisplayName) {
96+
mDisplayName(other.mDisplayName),
97+
mDomainName(other.mDomainName) {
7398
// Release the data pointer from the source object so that the destructor
7499
// does not free the memory multiple times.
75100
other.mEmailAddress = nullptr;
76101
other.mDisplayName = nullptr;
102+
other.mDomainName = nullptr;
77103
}
78104

79105
// Move assignement operator
80106
MessageAddress& MessageAddress::operator=(MessageAddress&& other) noexcept {
81107
if (this != &other) {
82108
delete[] mEmailAddress;
83109
delete[] mDisplayName;
110+
delete[] mDomainName;
84111
// Copy the data pointer and its length from the source object.
85112
mEmailAddress = other.mEmailAddress;
86113
mDisplayName = other.mDisplayName;
114+
mDomainName = other.mDomainName;
87115
// Release the data pointer from the source object so that
88116
// the destructor does not free the memory multiple times.
89117
other.mEmailAddress = nullptr;
90118
other.mDisplayName = nullptr;
119+
other.mDomainName = nullptr;
91120
}
92121
return *this;
93122
}
@@ -116,6 +145,10 @@ const char *MessageAddress::getDisplayName() const {
116145
return mDisplayName;
117146
}
118147

148+
const char *MessageAddress::getDomainName() const {
149+
return mDomainName;
150+
}
151+
119152
bool MessageAddress::isEmailAddressValid(const std::string &pEmailAddress) const {
120153
std::regex emailPattern("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$");
121154
return regex_match(StringUtils::toLower(pEmailAddress), emailPattern);

0 commit comments

Comments
 (0)