/
PJNSmtp.cpp
5501 lines (5042 loc) · 229 KB
/
PJNSmtp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Module : PJNSmtp.cpp
Purpose: Implementation for a MFC class encapsulation of the SMTP protocol
Created: PJN / 22-05-1998
History: PJN / 15-06-1998 1. Fixed the case where a single dot occurs on its own
in the body of a message
2. Class now supports Reply-To Header Field
3. Class now supports file attachments
PJN / 18-06-1998 1. Fixed a memory overwrite problem which was occurring
with the buffer used for encoding base64 attachments
PJN / 27-06-1998 1. The case where a line begins with a "." but contains
other text is now also catered for. See RFC821, Section 4.5.2
for further details.
2. m_sBody in CPJNSMTPMessage has now been made protected.
Client applications now should call AddBody instead. This
ensures that FixSingleDot is only called once even if the
same message is sent a number of times.
3. Fixed a number of problems with how the MIME boundaries
were defined and sent.
4. Got rid of an unreferenced formal parameter
compiler warning when doing a release build
PJN / 11-09-1998 1. VC 5 project file is now provided
2. Attachment array which the message class contains now uses
references instead of pointers.
3. Now uses Sleep(0) to yield our time slice instead of Sleep(100),
this is the preferred way of writting polling style code in Win32
without serverly impacting performance.
4. All Trace statements now display the value as returned from
GetLastError
5. A number of extra asserts have been added
6. A AddMultipleRecipients function has been added which supports added a
number of recipients at one time from a single string
7. Extra trace statements have been added to help in debugging
PJN / 12-09-1998 1. Removed a couple of unreferenced variable compiler warnings when code
was compiled with Visual C++ 6.0
2. Fixed a major bug which was causing an ASSERT when the CSMTPAttachment
destructor was being called in the InitInstance of the sample app.
This was inadvertingly introduced for the 1.2 release. The fix is to revert
fix 2. as done on 11-09-1998. This will also help to reduce the number of
attachment images kept in memory at one time.
PJN / 18-01-1999 1. Full CC & BCC support has been added to the classes
PJN / 22-02-1999 1. Addition of a Get and SetTitle function which allows a files attachment
title to be different that the original filename
2. AddMultipleRecipients now ignores addresses if they are empty.
3. Improved the reading of responses back from the server by implementing
a growable receive buffer
4. timeout is now 60 seconds when building for debug
PJN / 25-03-1999 1. Now sleeps for 250 ms instead of yielding the time slice. This helps
reduce CPU usage when waiting for data to arrive in the socket
PJN / 14-05-1999 1. Fixed a bug with the way the code generates time zone fields in the Date headers.
PJN / 10-09-1999 1. Improved CPJNSMTPMessage::GetHeader to include mime field even when no attachments
are included.
PJN / 16-02-2000 1. Fixed a problem which was occuring when code was compiled with VC++ 6.0.
PJN / 19-03-2000 1. Fixed a problem in GetHeader on Non-English Windows machines
2. Now ships with a VC 5 workspace. I accidentally shipped a VC 6 version in one of the previous versions of the code.
3. Fixed a number of UNICODE problems
4. Updated the sample app to deliberately assert before connecting to the author's SMTP server.
PJN / 28-03-2000 1. Set the release mode timeout to be 10 seconds. 2 seconds was causing problems for slow dial
up networking connections.
PJN / 07-05-2000 1. Addition of some ASSERT's in CPJNSMTPSocket::Connect
PP / 16-06-2000 The following modifications were done by Puneet Pawaia
1. Removed the base64 encoder from this file
2. Added the base64 encoder/decoder implementation in a separate
file. This was done because base64 decoding was not part of
the previous implementation
3. Added support for ESMTP connection. The class now attempts to
authenticate the user on the ESMTP server using the username and
passwords supplied. For this connect now takes the username and
passwords as parameters. These can be null in which case ESMTP
authentication is not attempted
4. This class can now handle AUTH LOGIN and AUTH LOGIN PLAIN authentication
schemes on
PP / 19-06-2000 The following modifications were done by Puneet Pawaia
1. Added the files md5.* containing the MD5 digest generation code
after modifications so that it compiles with VC++ 6
2. Added the CRAM-MD5 login procedure.
PJN / 10-07-2000 1. Fixed a problem with sending attachments > 1K in size
2. Changed the parameters to CPJNSMTPConnection::Connect
PJN / 30-07-2000 1. Fixed a bug in AuthLogin which was transmitting the username and password
with an extra "=" which was causing the login to failure. Thanks to Victor Vogelpoel for
finding this.
PJN / 05-09-2000 1. Added a CSMTP_NORSA preprocessor macro to allow the CPJNSMTPConnection code to be compiled
without the dependence on the RSA code.
PJN / 28-12-2000 1. Removed an unused variable from ConnectESMTP.
2. Allowed the hostname as sent in the HELO command to be specified at run time
in addition to using the hostname of the client machine
3. Fixed a problem where high ascii characters were not being properly encoded in
the quoted-printable version of the body sent.
4. Added support for user definable charset's for the message body.
5. Mime boundaries are now always sent irrespective if whether attachments are included or
not. This is required as the body is using quoted-printable.
6. Fixed a bug in sendLines which was causing small message bodies to be sent incorrectly
7. Now fully supports custom headers in the SMTP message
8. Fixed a copy and paste bug where the default port for the SMTP socket class was 110.
9. You can now specify the address on which the socket is bound. This enables the programmer
to decide on which NIC data should be sent from. This is especially useful on a machine
with multiple IP addresses.
10. Addition of functions in the SMTP connection class to auto dial and auto disconnect to
the Internet if you so desire.
11. Sample app has been improved to allow Auto Dial and binding to IP addresses to be configured.
PJN / 26-02-2001 1. Charset now defaults to ISO 8859-1 instead of us-ascii
2. Removed a number of unreferrenced variables from the sample app.
3. Headers are now encoded if they contain non ascii characters.
4. Fixed a bug in getLine, Thanks to Lev Evert for spotting this one.
5. Made the charset value a member of the message class instead of the connection class
6. Sample app now fully supports specifying the charset of the message
7. Added a AddMultipleAttachments method to CPJNSMTPMessage
8. Attachments can now be copied to each other via new methods in CSMTPAttachment
9. Message class now contains copies of the attachments instead of pointers to them
10. Sample app now allows multiple attachments to be added
11. Removed an unnecessary assert in QuotedPrintableEncode
12. Added a Mime flag to the CPJNSMTPMessage class which allows you to decide whether or not a message
should be sent as MIME. Note that if you have attachments, then mime is assumed.
13. CSMTPAttachment class has now become CPJNSMTPBodyPart in anticipation of full support for MIME and
MHTML email support
14. Updated copright message in source code and documentation
15. Fixed a bug in GetHeader related to _tsetlocale usage. Thanks to Sean McKinnon for spotting this
problem.
16. Fixed a bug in SendLines when sending small attachments. Thanks to Deng Tao for spotting this
problem.
17. Removed the need for SendLines function entirely.
18. Now fully supports HTML email (aka MHTML)
19. Updated copyright messages in code and in documentation
PJN / 17-06-2001 1. Fixed a bug in CPJNSMTPMessage::HeaderEncode where spaces were not being interpreted correctly. Thanks
to Jim Alberico for spotting this.
2. Fixed 2 issues with ReadResponse both having to do with multi-line responses. Thanks to Chris Hanson
for this update.
PJN / 25-06-2001 1. Code now links in Winsock and RPCRT40 automatically. This avoids client code having to specify it in
their linker settings. Thanks to Malte and Phillip for spotting this issue.
2. Updated sample code in documentation. Thanks to Phillip for spotting this.
3. Improved the code in CPJNSMTPBodyPart::SetText to ensure lines are correctly wrapped. Thanks to
Thomas Moser for this fix.
PJN / 01-07-2001 1. Modified QuotedPrintableEncode to prevent the code to enter in an infinite loop due to a long word i.e.
bigger than SMTP_MAXLINE, in this case, the word is breaked. Thanks to Manuel Gustavo Saraiva for this fix.
2. Provided a new protected variable in CPJNSMTPBodyPart called m_bQuotedPrintable to bypass the
QuotedPrintableEncode function in cases that we don't want that kind of correction. Again thanks to
Manuel Gustavo Saraiva for this fix.
PJN / 15-07-2001 1. Improved the error handling in the function CPJNSMTPMessage::AddMultipleAttachments. In addition the
return value has been changed from BOOL to int
PJN / 11-08-2001 1. Fixed a bug in QuotedPrintableEncode which was wrapping encoding characters across multiple lines.
Thanks to Roy He for spotting this.
2. Provided a "SendMessage" method which sends a email directly from disk. This allows you
to construct your own emails and the use the class just to do the sending. This function also has the
advantage that it efficiently uses memory and reports progress.
3. Provided support for progress notification and cancelling via the "OnSendProgress" virtual method.
PJN / 29-09-2001 1. Fixed a bug in ReadResponse which occured when you disconnected via Dial-Up Networking
while a connection was active. This was originally spotted in my POP3 class.
2. Fixed a problem in CPJNSMTPBodyPart::GetHeader which was always including the "quoted-printable" even when
m_bQuotedPrintable for that body part was FALSE. Thanks to "jason" for spotting this.
PJN / 12-10-2001 1. Fixed a problem where GetBody was reporting the size as 1 bigger than it should have been. Thanks
to "c f" for spotting this problem.
2. Fixed a bug in the TRACE statements when a socket connection cannot be made.
3. The sample app now displays a filter of "All Files" when selecting attachments to send
4. Fixed a problem sending 0 byte attachments. Thanks to Deng Tao for spotting this problem.
PJN / 11-01-2002 1. Now includes a method to send a message directly from memory. Thanks to Tom Allebrandi for this
suggestion.
2. Change function name "IsReadible" to be "IsReadable". I was never very good at English!.
3. Fixed a bug in CPJNSMTPBodyPart::QuotedPrintableEncode. If a line was exactly 76 characters long plus
\r\n it produced an invalid soft linebreak of "\r=\r\n\n". Thanks to Gerald Egert for spotting this problem.
PJN / 29-07-2002 1. Fixed an access violation in CPJNSMTPBodyPart::QuotedPrintableEncode. Thanks to Fergus Gallagher for
spotting this problem.
2. Fixed a problem where in very rare cases, the QuotedPrintableEncode function produces a single dot in a
line, when inserting the "=" to avoid the mail server's maxline limit. I inserted a call to FixSingleDot
after calling the QuotedPrintableEncode function in GetBody. Thanks to Andreas Kappler for spotting this
problem.
3. Fixed an issue in CPJNSMTPBodyPart::GetHeader where to ensure some mail clients can correctly handle
body parts and attachments which have a filename with spaces in it. Thanks to Andreas kappler for spotting
this problem.
4. QP encoding is now only used when you specify MIME. This fixes a bug as reported by David Terracino.
5. Removed now unused "API Reference" link in HTML file supported the code.
PJN / 10-08-2002 1. Fixed a number of uncaught file exceptions in CPJNSMTPBodyPart::GetBody, CPJNSMTPMessage::SaveToDisk, and
CPJNSMTPConnection::SendMessage. Thanks to John Allan Miller for reporting this problem.
2. The CPJNSMTPConnection::SendMessage version of the method which sends a file directly from disk, now fails if the
file is empty.
3. Improved the sample app by displaying a wait cursor while a message from file is being sent
4. Improved the sample app by warning the user if mail settings are missing and then bringing up the configuration
dialog.
PJN / 20-09-2002 1. Fixed a problem where the code "Coder.EncodedMessage" was not being converted from an ASCII string to a UNICODE
string in calls to CString::Format. This was occurring when sending the username and password for "AUTH LOGIN" support
in addition to sending the "username digest" for "AUTH CRAM-MD5" support. Thanks to Serhiy Pavlov for reporting this
problem.
2. Removed a number of calls to CString::Format and instead replaced with string literal CString constructors instead.
PJN / 03-10-2002 1. Quoted printable encoding didn't work properly in UNICODE. (invalid conversion from TCHAR to BYTE). Thanks to
Serhiy Pavlov for reporting this problem.
2. Subject encoding didn't work properly in UNICODE. (invalid conversion from TCHAR to BYTE). Thanks to Serhiy Pavlov
for reporting this problem.
3. It didn't insert "charset" tag into root header for plain text messages (now it includes "charset" into plain text
messages too). Thanks to Serhiy Pavlov for reporting this problem.
PJN / 04-10-2002 1. Fixed an issue where the header / body separator was not being sent correctly for mails with attachments or when
the message is MIME encoded. Thanks to Serhiy Pavlov for reporting this problem.
2. Fixed a bug in QuotedPrintableEncode and HeaderEncode which was causing the errors. Thanks to Antonio Maiorano
for reporting this problem.
3. Fixed an issue with an additional line separator being sent between the header and body of emails. This was only
evident in mail clients if a non mime email without attachments was sent.
PJN / 11-12-2002 1. Review all TRACE statements for correctness
2. Provided a virtual OnError method which gets called with error information
PJN / 07-02-2003 1. Addition of a "BOOL bGracefully" argument to Disconnect so that when an application cancels the sending of a
message you can pass FALSE and close the socket without properly terminating the SMTP conversation. Thanks to
"nabocorp" for this nice addition.
PJN / 19-03-2003 1. Addition of copy constructors and operator= to CPJNSMTPMessage class. Thanks to Alexey Vasilyev for this suggestion.
PJN / 13-04-2003 1. Fixed a bug in the handling of EHLO responses. Thanks to "Senior" for the bug report and the fix.
PJN / 16-04-2003 1. Enhanced the CPJNSMTPAddress constructor to parse out the email address and friendly name rather than assume
it is an email address.
2. Reworked the syntax of the CPJNSMTPMessage::ParseMultipleRecipients method. Also now internally this function
uses the new CPJNSMTPAddress constructor
PJN / 19-04-2003 1. Fixed a bug in the CPJNSMTPAddress constructor where I was mixing up the friendly name in the "<>" separators,
when it should have been the email address.
PJN / 04-05-2003 1. Fixed an issue where the class doesn't convert the mail body and subject to the wanted encoding but rather changes
the encoding of the email in the email header. Since the issue of supporting several languages is a complicated one
I've decided that we could settle for sending all CPJNSMTPConnection emails in UTF-8. I've added some conversion functions
to the class that - at this point - always converts the body and subject of the email to UTF-8. A big thanks to Itamar
Kerbel for this nice addition.
2. Moved code and sample app to VC 6.
PJN / 05-05-2003 1. Reworked the way UTF8 encoding is now done. What you should do if you want to use UTF-8 encoding is set the charset
to "UTF-8" and use either QP or base 64 encoding.
2. Reworked the automatic encoding of the subject line to use the settings as taken from the root SMTP body part
3. Only the correct headers according to the MIME RFC are now encoded.
4. QP encoding is the encoding mechanism now always used for headers.
5. Headers are now only encoded if required to be encoded.
PJN / 12-05-2003 1. Fixed a bug where the X-Mailer header was being sent incorrectly. Thanks to Paolo Vernazza for reporting this problem.
2. Addition of X-Mailer header is now optional. In addition sample app now does not send the X-Mailer header.
3. The sample app now does not send the Reply-To header.
PJN / 18-08-2003 1. Modified the return value from the ConnectToInternet method. Instead of it being a boolean, it is now an enum. This
allows client code to differentiate between two conditions that it couldn't previously, namely when an internet connection
already existed or if a new connection (presumably a dial-up connection was made). This allows client code to then
disconnect if a new connection was required. Thanks to Pete Arends for this nice addition.
PJN / 05-10-2003 1. Reworked the CPJNSMTPConnection::ReadResponse method to use the timeout provided by IsReadable rather than calling sleep.
Thanks to Clarke Brunt for reporting this issue.
PJN / 03-11-2003 1. Simplified the code in CPJNSMTPConnection::ReadResponse. Thanks to Clarke Brunt for reporting this issue.
PJN / 03-12-2003 1. Made code which checks the Login responses which contain "Username" and "Password" case insensitive. Thanks to
Zhang xiao Pan for reporting this problem.
PJN / 11-12-2003 1. Fixed an unreferrenced variable in CPJNSMTPConnection::OnError as reported by VC.Net 2003
2. DEBUG_NEW macro is now only used on VC 6 and not on VC 7 or VC 7.1. This avoids a problem on these compilers
where a conflict exists between it and the STL header files. Thanks to Alex Evans for reporting this problem.
PJN / 31-01-2004 1. Fixed a bug in CPJNSMTPBodyPart::GetBody where the size of the body part was incorrectly calculating the size if the
encoded size was an exact multiple of 76. Thanks to Kurt Emanuelson and Enea Mansutti for reporting this problem.
PJN / 07-02-2004 1. Fixed a bug in CPJNSMTPBodyPart::SetText where the code would enter an endless loop in the Replace function. It has now
been replaced with CString::Replace. This now means that the class will not now compile on VC 5. Thanks to Johannes Philipp
Grohs for reporting this problem.
2. Fixed a number of warnings when the code is compiled with VC.Net 2003. Thanks to Edward Livingston for reporting
this issue.
PJN / 18-02-2004 1. You can now optionally set the priority of an email thro the variable CPJNSMTPMessage::m_Priority. Thanks to Edward
Livingston for suggesting this addition.
PJN / 04-03-2004 1. To avoid conflicts with the ATL Server class of the same name, namely "CSMTPConnection", the class is now called
"CPJNSMTPConnection". To provide for easy upgrading of code, "CSMTPConnection" is now defined to be "CPJSMTPConnection"
if the code detects that the ATL Server SMTP class is not included. Thanks to Ken Jones for reporting this issue.
PJN / 13-03-2004 1. Fixed a problem where the CPJNSMTPBodyPart::m_dwMaxAttachmentSize value was not being copied in the CPJNSMTPBodyPart::operator=
method. Thanks to Gerald Egert for reporting this problem and the fix.
PJN / 05-06-2004 1. Fixed a bug in CSMTPConnection::ReadResponse, where the wrong parameters were being null terminated. Thanks to "caowen"
for this update.
2. Updated the CSMTPConnection::ReadResponse function to handle multiline responses in all cases. Thanks to Thomas Liebethal
for reporting this issue.
PJN / 07-06-2004 1. Fixed a potential buffer overflow issue in CPJNSMTPConnection::ReadResponse when certain multi line responses are received
PJN / 30-09-2004 1. Fixed a parsing issue in CPJNSMTPConnection::ReadResponse when multi line responses are read in as multiple packets.
Thanks to Mark Smith for reporting this problem.
2. Reworked the code which supports the various authentication mechanisms to support the correct terms. What was called
"AUTH LOGIN PLAIN" support now more correctly uses the term "AUTH PLAIN". The names of the functions and enums have now
also been reworked.
3. Did a review of the sample app code provided with the class so that the name of the modules, projects, exe etc is now
"PJNSMTPApp". Also reworked the name of some helper classes as well as the module name which supports the main class.
4. Reworked CPJNSMTPConnection::AuthLoginPlain (now called AuthPlain) to correctly handle the case where an invalid
response is received when expecting the username: response. Thanks to Mark Smith for reporting this problem.
PJN / 23-12-2004 "Name" field in Content-Type headers is now quoted just like the filename field. Thanks to Mark Smith for reporting this
issue in conjunction with the mail client Eudora.
PJN / 23-01-2005 1. All classes now uses exceptions to indicate errors. This means the whole area of handling errors in the code a whole lot
simpler. For example the OnError mechanism is gone along with all the string literals in the code. The actual code itself
is a whole lot simpler also. You should carefully review your code as a lot of the return values from methods (especially
CPJNSMTPConnection) are now void and will throw CSMTPException's. Thanks to Mark Smith for prompting this update.
2. General tidy up of the code following the testing of the new exception based code.
PJN / 06-04-2005 1. Addition of PJNSMTP_EXT_CLASS define to the classes to allow the classes to be easily incorporated into extension DLLs.
Thanks to Arnaud Faucher for suggesting this addition.
2. Now support NTLM authentication. Thanks to Arnaud Faucher for this nice addition. NTLM Authentication is provided by
a new reusable class called "CNTLMClientAuth" in PJNNTLMAuth.cpp/h".
3. Fixed a bug in the sample app in the persistence of the Authentication setting. Thanks to Arnaud Faucher for reporting
this issue.
PJN / 26-03-2005 1. Fixed compile problems with the code when the Force Conformance In For Loop Scope compile setting is used in
Visual Studio .NET 2003. Thanks to Alexey Kuznetsov for reporting this problem.
2. Fixed compile problems when the code is compiled using the Detect 64-bit Portability Issues setting in Visual Studio
.NET 2003.
PJN / 18-04-2005 1. Addition of a simple IsConnected() function inline with the author's CPop3Connection class. Thanks to Alexey Kuznetsov
for prompting this addition.
2. Addition of a MXLookup function which provides for convenient DNS lookups of MX records (the IP addresses of SMTP mail
servers for a specific host domain). Internally this new function uses the new DNS functions which are provided with
Windows 2000 or later. To ensure that the code continues to work correctly on earlier versions of Windows, the function
pointers for the required functions are constructed at runtime using GetProcAddress. You can use this function to
discover the IP address of the mail servers responsible for a specific domain. This allows you to deliver email directly
to a domain rather than through a third party mail server. Thanks to Hans Dietrich for suggesting this nice addition.
PJN / 23-04-2005 1. The code now uses a MS Crypto API implementation of the MD5 HMAC algorithm instead of custom code based on the RSA
MD5 code. This means that there is no need for the RSA MD5.cpp, MD5.h and glob-md5.h to be included in client applications.
In addition the build configurations for excluding the RSA MD5 code has been removed from the sample app. The new classes to
perform the MD5 hashing are contained in PJNMD5.h and are generic enough to be included in client applications in their
own right.
PJN / 01-05-2005 1. Now uses the author'ss CWSocket sockets wrapper class.
2. Added support for connecting via Socks4, Socks5 and HTTP proxies
3. The last parameter to Connect has now been removed and is configured via an accessor / mutator pair Get/SetBoundAddress.
4. CSMTPException class is now called CPJNSMTPException.
5. Class now uses the Base64 class as provided with CWSocket. This means that the modules Base64Coder.cpp/h are no longer
distributed or required and should be removed from any projects which use the updated SMTP classes.
6. Fixed a bug in SaveToDisk method whereby existing files were not being truncated prior to saving the email message.
7. All calls to allocate heap memory now generate a CPJNSMTPException if the allocation fails.
8. Addition of a MXLookupAvailable() function so that client code can know a priori if DNS MX lookups are supported.
9. Sample app now allows you to use the MXLookup method to determine the mail server to use based on the first email address
you provide in the To field.
PJN / 03-05-2005 1. Fixed a number of warnings when the code is compiled in Visual Studio .NET 2003. Thanks to Nigel Delaforce for
reporting these issues.
PJN / 24-07-2005 1. Now includes support for parsing "(...)" comments in addresses. Thanks to Alexey Kuznetsov for this nice addition.
2. Fixed an issue where the mail header could contain a "Content-Transfer-Encoding" header. This header should only be
applied to headers of MIME body parts rather than the mail header itself. Thanks to Jeroen van der Laarse, Terence Dwyer
and Bostjan Erzen for reporting this issue and the required fix.
3. Now calling both AddTextBody and AddHTMLBody both set the root body part MIME type to multipart/mixed. Previously
the code comments said one thing and did another (set it to "multipart/related"). Thanks to Bostjan Erzen for reporting
this issue.
PJN / 14-08-2005 1. Minor update to include comments next to various locations in the code to inform users what to do if they get compile
errors as a result of compiling the code without the Platform SDK being installed. Thanks to Gudjon Adalsteinsson for
prompting this update.
2. Fixed an issue when the code calls the function DnsQuery when the code is compiled for UNICODE. This was the result of
a documentation error in the Platform SDK which incorrectly says that DnsQuery_W takes a ASCII string when in actual fact
it takes a UNICODE string. Thanks to John Oustalet III for reporting this issue.
PJN / 05-09-2005 1. Fixed an issue in MXLookup method where memory was not being freed correctly in the call to DnsRecordListFree. Thanks
to Raimund Mettendorf for reporting this bug.
2. Fixed an issue where lines which had a single dot i.e. "." did not get mailed correctly. Thanks to Raimund Mettendorf
for reporting this issue.
3. Removed the call to FixSingleDot from SetText method as it is done at runtime as the email as being sent. This was
causing problems for fixing up the dot issue when MIME encoded messages were being sent.
4. Fixed an issue where the FixSingleDot function was being called when saving a message to disk. This was incorrect
and it should only be done when actually sending an SMTP email.
PJN / 07-09-2005 1. Fixed another single dot issue, this time where the body is composed of just a single dot. Thanks to Raimund Mettendorf
for reporting this issue.
2. Fixed a typo in the accessor function CPJNSMTPConnection::GetBoundAddress which was incorrectly called
CPJNSMTPConnection::SetBoundAddress.
PJN / 29-09-2005 1. Removed linkage to secur32.lib as all SSPI functions are now constructed at runtime using GetProcAddress. Thanks to
Emir Kapic for this update.
2. 250 or 251 is now considered a successful response to the RCPT command. Thanks to Jian Peng for reporting this issue.
3. Fixed potential memory leaks in the implementation of NTLM authentication as the code was throwing exceptions
which the authentication code was not expected to handle.
PJN / 02-10-2005 1. MXLookup functionality of the class can now be excluded via the preprocessor define "CPJNSMTP_NOMXLOOKUP". Thanks to
Thiago Luiz for prompting this update.
2. Sample app now does not bother asking for username and password if authentication type is NTLM. Thanks to Emir Kapic
for spotting this issue.
3. Documentation has been updated to refer to issues with NTLM Authentication and SSPI. Thanks to Emir Kapic for prompting
this update.
4. Fixed an update error done for the previous version which incorrectly supported the additional 251 command for the "MAIL"
command instead of more correctly the "RCPT" command. Thanks to Jian Peng for reporting this issue.
PJN / 07-10-2005 1. Fixed an issue where file attachments were incorrectly including a charset value in their headers. Thanks to Asle Rokstad
for reporting this issue.
PJN / 16-11-2005 1. Now includes full support for connecting via SSL. For example sending mail thro Gmail using the server
"smtp.gmail.com" on port 465. Thanks to Vladimir Sukhoy for providing this very nice addition (using of course the author's
very own OpenSSL wrappers!).
PJN / 29-06-2006 1. Code now uses new C++ style casts rather than old style C casts where necessary.
2. Integrated ThrowPJNSMTPException function into CPJNSMTPConnection class and renamed to ThrowPJNSMTPException
3. Combined the functionality of the _PJNSMTP_DATA class into the main CPJNSMTPConnection class.
4. Updated the code to clean compile on VC 2005
5. Updated copyright details.
6. Removed unnecessary checks for failure to allocate via new since in MFC these will throw CMemoryExceptions!.
7. Optimized CPJNSMTPException constructor code
PJN / 14-07-2006 1. Fixed a bug in CPJNSMTPConnection where when compiled in UNICODE mode, NTLM authentication would fail. Thanks to
Wouter Demuynck for providing the fix for this bug.
2. Reworked the CPJNSMTPConnection::NTLMAuthPhase(*) methods to throw standard CPJNSMTPException exceptions if there are any
problems detected. This can be done now that the CNTLMClientAuth class is resilient to exceptions being thrown.
PJN / 17-07-2006 1. Updated the code in the sample app to allow > 30000 characters to be entered into the edit box which contains the body
of the email. This is achieved by placing a call to CEdit::SetLimitText in the OnInitDialog method of the dialog. Thanks to
Thomas Noone for reporting this issue.
PJN / 13-10-2006 1. Fixed an issue in Disconnect where if the call to ReadCommandResponse threw an exception, we would not close down the
socket or set m_bConnected to FALSE. The code has been updated to ensure these are now done. This just provides a more
consistent debugging experience. Thanks to Alexey Kuznetsov for reporting this issue.
2. CPJNSMTPException::GetErrorMessage now uses the user default locale for formatting error strings.
3. CPJNSMTPMessage::ParseMultipleRecipients now supports email addresses of the form ""Friendly, More Friendly" <emailaddress>"
Thanks to Xiao-li Ling for this very nice addition.
4. Fixed some issues with cleaning up of header and body parts in CPJNSMTPConnection::SendBodyPart and
CPJNSMTPMessage::WriteToDisk. Thanks to Xiao-li Ling for reporting this issue.
PJN / 09-11-2006 1. Reverted CPJNSMTPException::GetErrorMessage to use the system default locale. This is consistent with how MFC
does its own error handling.
2. Now includes comprehensive support for DSN's (Delivery Status Notifications) as specified in RFC 3461. Thanks to
Riccardo Raccuglia for prompting this update.
3. CPJNSMTPBodyPart::GetBody and CPJNSMTPConnection::SendMessage(const CString& sMessageOnFile... now does not open the disk
file for exclusive read access, meaning that other apps can read from the file. Thanks to Wouter Demuynck for reporting
this issue.
4. Fixed an issue in CPJNSMTPConnection::SendMessage(const CString& sMessageOnFile... where under certain circumstances
we could end up deleting the local "pSendBuf" buffer twice. Thanks to Izidor Rozman for reporting this issue.
PJN / 30-03-2007 1. Fixed a bug in CPJNSMTPConnection::SetHeloHostname where an unitialized stack variable could potentially be used. Thanks
to Anthony Kowalski for reporting this bug.
2. Updated copyright details.
PJN / 01-08-2007 1. AuthCramMD5, ConnectESMTP, ConnectSMTP, AuthLogin, and AuthPlain methods have now been made virtual.
2. Now includes support for a Auto Authentication protocol. This will detect what authentication methods the SMTP server
supports and uses the "most secure" method available. If you do not agree with the order in which the protocol is chosen,
a virtual function called "ChooseAuthenticationMethod" is provided. Thanks to "zhangbo" for providing this very nice
addition to the code.
3. Removed the definition for the defunct "AuthNTLM" method.
PJN / 13-11-2007 1. Major update to the code to use VC2005 specific features. This version of the code and onwards will be supported only
on VC 2005 or later. Thanks to Andrey Babushkin for prompting this update. Please note that there has been breaking changes
to the names and layout of various methods and member variables. You should carefully analyze the sample app included in the
download as well as your client code for the required updates you will need to make.
2. Sample app included in download is now build for Unicode and links dynamically to MFC. It also links dynamically to the
latest OpenSSL 0.9.8g dlls.
PJN / 19-11-2007 1. The "Date:" header is now formed using static lookup arrays for the day of week and month names instead of using
CTime::Format. This helps avoid generating invalid Date headers on non English version of Windows where the local language
versions of these strings would end up being used. Thanks to feedback at the codeproject page for the bug report (specifically
http://www.codeproject.com/internet/csmtpconn.asp?df=100&forumid=472&mpp=50&select=2054493#xx2054493xx for reporting this issue).
PJN / 22-12-2007 1. Following feedback from Selwyn Stevens that the AUTH PLAIN mechanism was failing for him while trying to send mail using the
gmail SMTP server, I decided to go back and re-research the area of SMTP authentication again<g>. It turns out that the way I was
implementing AUTH PLAIN support was not the same as that specified in the relevant RFCs. The code has now been updated to be
compliant with that specified in the RFC. I've confirmed the fix as operating correctly by using the gmail SMTP mail server
at "smtp.gmail.com" on the SMTP/SSL port of 465. I've also taken the opportunity to update the documentation to include a section
with links to various RFC's and web pages for background reference material
PJN / 24-12-2007 1. CPJNSMTPException::GetErrorMessage now uses the FORMAT_MESSAGE_IGNORE_INSERTS flag. For more information please see Raymond
Chen's blog at http://blogs.msdn.com/oldnewthing/archive/2007/11/28/6564257.aspx. Thanks to Alexey Kuznetsov for reporting this
issue.
2. All username and password temp strings are now securely destroyed using SecureZeroMemory.
PJN / 31-12-2007 1. Updated the sample app to clean compile on VC 2008
2. Fixed a x64 compile problems in RemoveCustomHeader & AddMultipleAttachments.
3. Fixed a x64 compile problem in CPJNSMTPAppConfigurationDlg::CBAddStringAndData
4. CPJNSMTPException::GetErrorMessage now uses Checked::tcsncpy_s
5. Other Minor coding updates to CPJNSMTPException::GetErrorMessage
PJN / 02-02-2008 1. Updated copyright details.
2. Fixed a bug in CPJNSMTPMessage::FormDateHeader where sometimes an invalid "Date:" header is created. The bug will manifest
itself for anywhere that is ahead of GMT, where the difference isn't a multiple of one hour. According to the Windows Time Zone
applet, this bug would have occured in: Tehran, Kabul, Chennai, Kolkata, Mumbai, New Delhi, Sri Jayawardenepura, Kathmandu, Yangon,
Adelaide and Darwin. Thanks to Selwyn Stevens for reporting this bug and providing the fix.
PJN / 01-03-2008 1. CPJNSMTP Priority enum values, specifically NO_PRIORITY have been renamed to avoid clashing with a #define of the same name in the
Windows SDK header file WinSpool.h. The enum values for DSN_RETURN_TYPE have also been renamed to maintain consistency. Thanks to
Zoran Buntic for reporting this issue.
2. Fixed compile problems related to the recent changes in the Base64 class. Thanks to Mat Berchtold for reporting this issue.
3. Since the code is now for VC 2005 or later only, the code now uses the Base64 encoding support from the ATL atlenc.h header file.
Thanks to Mat Berchtold for reporting this optimization. This means that client projects no longer need to include Base64.cpp/h in
their projects.
PJN / 31-05-2008 1. Code now compiles cleanly using Code Analysis (/analyze)
2. Removed the use of the function QuotedPrintableEncode and replaced with ATL::QPEncode
3. Removed the use of the function QEncode and replaced with ATL::QEncode
4. Reworked ReadResponse to use CStringA in line with the implementation in the POP3 class of the author.
PJN / 20-07-2008 1. Fixed a bug in ReadResponse where the code is determining if it has received the terminator. Thanks to Tony Cool for reporting
this bug.
PJN / 27-07-2008 1. Updated code to compile correctly using _ATL_CSTRING_EXPLICIT_CONSTRUCTORS define
2. CPJNSMTPMessage::GetHeader now correctly ensures all long headers are properly folded. In addition this function has been reworked
to create the header internally as an ASCII string rather than as a TCHAR style CString.
PJN / 16-08-2008 1. Updated the AUTH_AUTO login support to fall back to no authentication if no authentication scheme is supported by the SMTP server.
Thanks to Mat Berchtold for this update.
PJN / 02-11-2008 1. Improvements to CPJNSMTPAddress constructor which takes a single string. The code now removes redundant quotes.
2. CPJNSMTPAddress::GetRegularFormat now forms the regular form of the email address before it Q encodes it
3. The sample app now uses DPAPI to encrypt the username & password configuration settings
4. The sample app is now linked against the latest OpenSSL v0.9.8i dlls
4. Updated coding references in the html documentation. In addition the zip file now includes the OpenSSL dlls. Thanks to Michael
Grove for reporting this issues.
PJN / 03-11-2008 1. For best compatibility purposes with existing SMTP mail servers, all message headers which include email addresses are now not
Q encoded. Also the friendly part of the email address is quoted. Thanks to Christian Egging for reporting this issue.
2. Optimized use of CT2A class throughout the code
PJN / 25-06-2009 1. Updated copyright details
2. Fixed a bug where the Reply-To email address was not correctly added to the message. Thanks to Dmitriy Maksimov for reporting this
issue.
3. Updated the sample app's project settings to more modern default values.
4. Updated the sample exe to ship with OpenSSL v0.98k
5. Fixed a bug in CPJNSMTPConnection::SendBodyPart where it would cause errors from OpenSSL when trying to send a body of 0 bytes in size.
This can occur when MHTML based emails are sent and you are using a "multipart/related" body part. Thanks to "atota" for reporting this
issue
PJN / 13-11-2009 1. Now includes comprehensive support for MDN's (Message Disposition Notifications) as specified in RFC 3798. Thanks to
Ron Brunton for prompting this update.
2. Rewrote CPJNSMTPMessage::SaveToDisk method to use CAtlFile
PJN / 17-12-2009 1. The sample app is now linked against the latest OpenSSL v0.9.8l dlls
2. Updated the sample code in the documentation to better describe how to use the various classes. Thanks to Dionisis Kofos for reporting
this issue.
PJN / 23-05-2010 1. Updated copyright details
2. Updated sample app to compile cleanly on Visual Studio 2010
3. The sample app is now linked against the latest OpenSSL v1.0.0 dlls
4. Removed an unused "sRet" variable in CPJNSMTPConnection::AuthCramMD5. THanks to Alain Danteny for reporting this issue.
5. Replaced all calls to memcpy with memcpy_s
6. The code now supports STARTTLS encryption as defined in RFC 3207.
7. If the call to DnsQuery fails, the error value is now preserved using SetLastError
8. AddTextBody now sets the mime type of the root body part multipart/alternative. This is a more appropriate value to use which is better
supported by more email clients. Thanks to Thane Hubbell for reporting this issue.
PJN / 04-06-2010 1. Updated the code and sample app to compile cleanly when CPJNSMTP_NOSSL is defined. Thanks to "loggerlogger" for reporting this issue.
PJN / 10-07-2010 1. Following feedback from multiple users of PJNSMTP, including Chris Bamford and "loggerlogger", the change from "multipart/mixed" to
"multipart/alternative" has now been reverted. Using "multipart/mixed" is a more appropriate value to use. Testing by various clients
have shown that this setting works correctly when sending HTML based email in GMail, Thunderbird and Outlook. Unfortunately this is the
price I must pay when accepting end user contributions to my code base which I cannot easily test. Going forward I plan to be much more
discerning on what modifications I will accept to avoid these issues.
2. The CPJNSMTPBodyPart now has the concept of whether or not the body is considered an attachment. Previously the code assumed that if
you set the m_sFilename parameter that the body part was an attachment. Instead now the code uses the "m_bAttachment" member variable.
This allows an in memory representation of an attachment to be added to a message without the need to write it to an intermediate file
first. For example, here would be the series of steps you would need to go through to add an in memory jpeg image to an email and have it
appear as an attachment:
const BYTE* pInMemoryImage = pointer to your image;
DWORD dwMemoryImageSize = size in bytes of pInMemoryImage;
CPJNSMPTBase64Encode encode;
encode.Encode(pInMemoryImage, dwMemoryImageSize, ATL_BASE64_FLAG_NONE);
CPJNSMTPBodyPart imageBodyPart;
imageBodyPart.SetRawBody(encode.Result());
imageBodyPart.SetAttachment(TRUE);
imageBodyPart.SetContentType(_T("image/jpg"));
imageBodyPart.SetTitle(_T("the name of the image"));
CPJNSMTPMessage message;
message.AddBodyPart(imageBodyPart);
Thanks to Stephan Eizinga for suggesting this nice addition.
PJN / 28-11-2010 1. AddTextBody and AddHTMLBody now allow the root body part's MIME type to be changed. Thanks to Thane Hubbell for prompting this update.
2. Added a CPJNSMTPBodyPart::GetBoundary method.
3. Added some sample code to the sample app's CPJNSMTPAppDlg constructor to show how to create a message used SMTP body parts. Thanks to
Thane Hubbell for prompting this update.
4. CPJNSMTPBodyPart::GetHeader now allows quoted-printable and raw attachments to be used
5. The sample app is now linked against the latest OpenSSL v1.0.0b dlls
PJN / 18-12-2010 1. Remove the methods Set/GetQuotedPrintable and Set/GetBase64 from CPJNSMTPBodyPart and replaced them with new
Set/GetContentTransferEncoding methods which works with a simple enum.
2. CPJNSMTPBodyPart::SetAttachment and CPJNSMTPBodyPart::SetFilename now automatically sets the Content-Transfer-Encoding to base64 for
attachments. Thanks to Christian Egging for reporting this issue.
3. The sample app is now linked against the latest OpenSSL v1.0.0c dlls
PJN / 08-02-2011 1. Updated copyright details
2. Updated code to support latest SSL and Sockets class from the author. This means that the code now supports IPv6 SMTP servers
3. Connect method now allows binding to a specific IP address
PJN / 13-02-2011 1. Remove the IP binding address parameter from the Connect method as there was already support for binding via the Set/GetBoundAddress
methods.
2. Set/GetBoundAddress have been renamed Set/GetBindAddress for consistency with the sockets class
PJN / 01-04-2011 1. Reintroduced the concept of Address Header encoding. By default this setting is off, but can be enabled via a new
CPJNSMPTMessage::m_bAddressHeaderEncoding boolean value. Thanks to Bostjan Erzen for reporting this issue.
PJN / 04-12-2011 1. Updated CPJNSMTPBodyPart::GetHeader to encode the title of a filename if it contains non-ASCII characters. Thanks to Anders Gustafsson
for reporting this issue.
2. The sample app is now linked against the latst OpenSSL v1.0.0e dlls.
PJN / 12-08-2012 1. STARTTLS support code now uses TLSv1_client_method OpenSSL function instead of SSLv23_client_method. This fixes a problem where sending
emails using Hotmail / Windows Live was failing.
2. CPJNSMTPConnection::_Close now provides a bGracefully parameter
3. Updated the code to clean compile on VC 2012
4. The sample app is now linked against the latst OpenSSL v1.0.1c dlls.
5. SendMessage now throws a CPJNSMTPException if OnSendProgress returns FALSE.
6. Addition of a new ConnectionType called "AutoUpgradeToSTARTTLS" which will automatically upgrade a plain text connection to STARTTLS
if the code detects that the SMTP server supports STARTTLS. If the server doesn't support STARTTLS then the connection will remain as if
you specified "PlainText"
7. Reworked the code to determine if it should connect using EHLO instead of HELO into a new virtual method called DoEHLO.
8. Reworked the internals of the ConnectESMTP method.
PJN / 23-09-2012 1. Removed SetContentBase and GetContentBase methods as Content-Base header is deprecated from MHTML. For details see
http://www.ietf.org/mail-archive/web/apps-discuss/current/msg03220.html. Thanks to Mat Berchtold for reporting this issue.
2. Removed the now defunct parameter from the AddHTMLBody method.
3. Removed the FoldHeader method as it was only used by the m_sXMailer header.
4. Updated the logic in the FolderSubjectHeader method to correctly handle the last line of text to fold.
PJN / 24-09-2012 1. Removed an unnecessary line of code from CPJNSMTPConnection::SendRCPTForRecipient. Thanks to Mat Berchtold for reporting this issue.
PJN / 30-09-2012 1. Updated the code to avoid DLL planting security issues when calling LoadLibrary. Thanks to Mat Berchtold for reporting this issue.
PJN / 25-11-2012 1. Fixed some issues in the code when CPJNSMTP_NOSSL was defined. Looks like support for compiling without SSL support has been
broken for a few versions. Thanks to Bostjan Erzen for reporting this issue.
PJN / 12-03-2013 1. Updated copyright details.
2. CPJNSMTPAddressArray typedef is now defined in the CPJNSMTPMessage class instead of in the global namespace. In addition this typedef
class is now known as "CAddressArray"
3. The sample project included in the download now links to the various OpenSSL libraries via defines in stdafx.h instead of via project
settings. Thanks to Ed Nafziger for suggesting this nice addition.
4. The sample app no longer adds the author's hotmail address to the list of MDN's. Thanks to Ed Nafziger for spotting this.
5. The sample app is now linked against the latest OpenSSL v1.0.1e dlls.
6. Sample app now statically links to MFC
PJN / 03-06-2013 1. The demo app now disables the MIME checkbox after checking it if the email is to be sent as HTML
2. Fixed a bug in the sample app where the mime type of the root body part would be incorrectly set to an empty string when it should
use the default which is "multipart/mixed". Thanks to Ting L for reporting this bug.
PJN / 05-01-2014 1. Updated copyright details.
2. Updated the code to clean compile on VC 2013
3. Fixed a problem with NTLM auth where the code did not correctly set the "m_nSize" parameter value correctly in
CPJNSMPTBase64Encode::Encode & Decode. Thanks to John Pendleton for reporting this bug.
PJN / 18-01-2013 1. The ConvertToUTF8 method now also handles conversion of ASCII data to UTF8. Thanks to Jean-Christophe Voogden for this update.
2. The CPJNSMTPConnection class now provides Set/GetSSLProtocol methods. This allows client code to specify the exact flavour of SSL which
the code should speak. Supported protocols are SSL v2/v3, TLS v1.0, TLS v1.1, TLS v1.2 and DTLS v1.0. This is required for some SMTP
servers which use the SSLv2 or v3 protocol instead of the more modern TLS v1 protocol. The default is to use TLS v1.0.
You may need to use this compatibility setting for the likes of IBM Domino SMTP servers which only support the older SSLv2/v3 setting.
Thanks to Jean-Christophe Voogden for this update.
3. Removed all the proxy connection methods as they cannot be easily supported / tested by the author.
4. Reworked the code in CPJNSMTPConnection::ConnectESMTP to handle all variants of the 250 response as well as operate case insensitively
which is required by the ESMTP RFC.
5. Made more methods virtual to facilitate further client customisation
6. Fixed an issue in the DoSTARTTLS method where the socket would be left in a connected state if SSL negotiation failed. This would result in
later code which sent on the socket during the tear down phase hanging. Thanks to Jean-Christophe Voogden for reporting this issue.
7. The sample app is now linked against the latest OpenSSL v1.0.1f dlls.
PJN / 26-01-2014 1. Updated ASSERT logic at the top of the ConnectESMTP method. Thanks to Jean-Christophe Voogden for reporting this issue.
PJN / 09-02-2014 1. Fixed a compile problem in the CreateSSLSocket method when the CPJNSMTP_NOSSL preprocessor macro is defined.
2. Reworked the logic which does SecureZeroMemory on sensitive string data
PJN / 13-04-2014 1. The sample app is now linked against the latest OpenSSL v1.0.1g dlls. This version is the patched version of OpenSSL which does not
suffer from the Heartbleed bug.
2. Please note that by default OpenSSL does not do host name validation. The sample app provided with the PJNSMTP code also does not do
host name validation. This means that as it stands the sample app is vulnerable to man in the middle attacks if you use SSL/TLS to connect
to a SMTP server. For further information and sample code which you should incorporate into your real SMTP client applications, please see
http://wiki.openssl.org/index.php/Hostname_validation, https://github.com/iSECPartners/ssl-conservatory and
http://archives.seul.org/libevent/users/Feb-2013/msg00043.html.
PJN / 15-11-2014 1. Removed the defunct method CPJNSMTPBodyPart::HexDigit.
2. Reworked the CPJNSMTPBodyPart::GetBody method to use ATL::CAtlFile and ATL::CHeapPtr
3. CPJNSMTPConnection now takes a static dependency on Wininet.dll instead of using GetProcAddress.
4. CPJNSMTPConnection now takes a static dependency on Dnsapi.dll instead of using GetProcAddress.
5. The default timeout set in the CPJNSMTPConnection constructor is now 60 seconds for both debug and release builds
6. Removed the now defunct CPJNSMTPConnection::MXLookupAvailable method
7. Removed the now defunct CPJNSMTP_NOMXLOOKUP preprocessor value
8. Removed the now defunct PJNLoadLibraryFromSystem32.h module from the distribution
9. CPJNSMTPConnection::SendMessage has been reworked to use ATL::CAtlFile and ATL::CHeapPtr
10. CPJNSMTPConnection::SendMessage now does a UTF-8 conversion on the body of the email when sending
a plain email i.e. no HTML or mime if the charset is UTF-8. Thanks to Oliver Pfister for reporting this issue.
11. Sample app has been updated to compile cleanly on VS 2013 Update 3 and higher
12. The sample app shipped with the source code is now Visual Studio 2008 and as of this release the code is only supported on Visual Studio
2008 and later
13. The sample app is now linked against the latest OpenSSL v1.0.1j dlls
PJN / 18-11-2014 1. Fixed a bug in CPJNSMTPBodyPart::GetBody where file attachments were always being treated as 0 in size. Thanks to Oliver Pfister for
reporting this issue.
PJN / 14-12-2014 1. Updated the code to use the author's SSLWrappers classes (http://www.naughter.com/sslwrappers.html) to provide the SSL functionality
for PJNSMTP instead of OpenSSL. Please note that the SSLWrappers classes itself depends on the author's CryptoWrappers classes
(http://www.naughter.com/cryptowrappers.html) also. You will need to download both of these libraries and copy their modules into the
PJNSMTP directory. Also note that the SSLWrappers and CryptoWrapper classes are only supported on VC 2013 or later and this means that
the PJNSMTP SSL support is only supported when you compile with VC 2013 or later. The solution files included in the download is now for
VC 2013.
2. With the change to using SSLWrappers, the code can now support additional flavours of SSL protocol. They are: SSL v2 on its own,
SSL v3 on its own, The OS SChannel SSL default and AnyTLS. Please see the CPJNSMTPConnection::SSLProtocol enum for more details. The
sample app has been updated to allow these values to be used and the default enum value is now "OSDefault".
PJN / 16-12-2014 1. Updated the code to use the latest v1.03 version of SSLWrappers
PJN / 16-01-2015 1. Updated copright details
2. CPJNSMTPMessage::m_ReplyTo is now an array instead of a single address. Thanks to Bostjan Erzen for suggesting this update.
PJN / 25-01-2015 1. Addition of CPJNSMTPBodyPart::InsertChildBodyPart and CPJNSMTPMessage::InsertBodyPart methods. These new methods inserts a body part
as the first element in the hierarchy of child body parts instead of to the end. In addition the CPJNSMTPMessage::AddTextBody
and CPJNSMTPMessage::AddHTMLBody methods now call CPJNSMTPBodyPart::InsertChildBodyPart instead of CPJNSMTPBodyPart::AddChildBodyPart
to ensure that the body text part of the SMTP message appears as the first child body part. This helps avoid issues where Microsoft
Exchange modifies multipart messages where the body text is moved to an attachment called ATT00001: For further information please see
http://kb.mit.edu/confluence/pages/viewpage.action?pageId=4981187 and http://support2.microsoft.com/kb/969854. Thanks to Marco Veldman
for reporting this issue.
2. Removed support for DTLSv1 SSL protocol as this is not applicable to SMTP as DTLS is designed for UDP and not TCP. This removal helps
resolve an issue where the code did not compile in VC 2013 if you used the "Visual Studio 2013 - Windows XP (v120_xp)" Platform Toolset.
Thanks to Bostjan Erzen for reporting this issue.
PJN / 31-01-2015 1. Fixed an error in CPJNSMTPException::GetErrorMessage where it would not use the full HRESULT value when calling FormatMessage. Thanks
to Bostjan Erzen for reporting this issue.
2. Improved the error handling in CPJNSMTPConnection::Connect when SSL connection errors occur. Thanks to Bostjan Erzen for reporting
this issue.
3. Improved the error handling in CPJNSMTPConnection::DoSTARTTLS when SSL connection errors occur. Thanks to Bostjan Erzen for reporting
this issue.
PJN / 01-03-2015 1. The DoEHLO method has been updated to check for DSN requirements. This change means that the code will connect with a EHLO instead of
HELO when a DSN is requested. The code will now also check whether DSN's are supported by the server when attempting to send the DSN.
If the server does not support DSN's in this scenario then a new custom exception will be thrown by the code in the
CPJNSMTPConnection::FormMailFromCommand method. This ensures the code behaves more consistently with respect to the DSN RFC. Thanks to
Philip Mitchell for prompting this update.
2. Change the enum value for CPJNSMTPMessage::DSN_NOT_SPECIFIED to 0 from 0xFFFFFFFF.
PJN / 29-03-2015 1. Updated CPJNSMTPConnection::AuthLogin to handle more variants of "username:" and "password:" SMTP server responses. Thanks to Wang Le
for reporting this issue.
PJN / 01-06-2015 1. Removed unused CPJNSMTPMessage::ConvertHTMLToPlainText method.
2. Removed the linkage in the test app's configuration dialog between sending a message with a HTML body and requiring that the message
is MIME encoded.
3. Removed the code from the test app which added a plain text attachment to the message in debug builds.
4. Updated CPJNSMTPMessage::AddHTMLBody to handle the case where the message is not MIME encoded. In this case the root body part of the
message is simply set to HTML. Thanks to Thane Hubbell for reporting this issue.
PJN / 12-05-2016 1. Updated copyright details.
2. Minor update to the sample app to refer to "SSL / TLS" in the configuration dialog.
3. Verfied the code compiles cleanly using VC 2015.
PJN / 11-08-2016 1. Reworked the classes to optionally compile without MFC. By default the classes now use STL classes and idioms but if you define
CWSOCKET_MFC_EXTENSTIONS the classes will revert back to the MFC behaviour.
2. Reworked the CPJNSMPTBase64Encode class to use ATL::CHeapPtr
3. Reworked the CPJNSMPTQPEncode class to use ATL::CHeapPtr
4. Reworked the CPJNSMPTQEncode class to use ATL::CHeapPtr
5. Added SAL annotations to all the code
6. CPJNSMTPBodyPart::ConvertToUTF8 now internally uses ATL::CHeapPtr
7. The CPJNSMTPMessage::m_CustomHeaders member variable is now public. As such the
AddCustomHeader, GetCustomHeader, GetNumberOfCustomHeaders & RemoveCustomHeader
methods have been removed.
8. Removed unnecessary code which catches and rethrows a CPJNSMTPException exception from the version of CPJNSMTPConnection::SendMessage
which sends a message from a memory buffer
9. Reworked the CPJNSMTPMessage::ParseMultipleRecipients method to avoid the use of the C++ new allocator
10. Reworked the CPJNSMTPMessage::AddMultipleAttachments method to avoid the use of the C++ new allocator
11. Reworked the sample app to exercise the SendMessage method which sends from a memory buffer
PJN / 17-08-2016 1. Reworked CPJNSMTPConnection class to be inherited from SSLWrappers::CSocket. This allows
for easier overloading of the various SSLWrappers class framework virtual functions
PJN / 19-08-2016 1. Reworked the CPJNSMTPException::GetErrorMessage to not bother putting the last response into the return error message text.
2. CPJNSMTPConnection class is now protected inherited from SSLWrappers::CSocket.
PJN / 15-09-2016 1. Added support for XOAUTH2 authentication. For more information about this SMTP authentication mechanism please see
https://developers.google.com/gmail/xoauth2_protocol.
2. Reworked the CPJNSMTPConnection::AuthPlain to provide the userid in the authorization identity value. This is a more compatible form
of the auth request and avoids issues using AuthPlain against the gmail SMTP servers.
3. Added Initial Client Response (SASL-IR) support to the AuthLogin, AuthPlain & AuthXOAUTH2 methods. For more information about SASL-IR
please see https://tools.ietf.org/html/rfc4959.
PJN / 13-10-2016 1. Fixed a bug in the declaration of the CPJNSMTPConnection class when the CPJNSMTP_NONTLM preprocessor value is defined. Thanks to Chris
Korda for reporting this issue.
2. Provided a new overload of the CPJNSMTPBodyPart::AddChildBodyPart method to allow an already heap allocated bodyPart to be added.
3. Provided a new overload of the CPJNSMTPBodyPart::InsertChildBodyPart method to allow an already heap allocated bodyPart to be added.
4. Made most of the methods of CPJNSMTPBodyPart virtual to allow for easier end user customization of its functionality.
5. Provided a new overload of the CPJNSMTPMessage::AddChildBodyPart method to allow an already heap allocated bodyPart to be added.
6. Provided a new overload of the CPJNSMTPMessage::InsertChildBodyPart method to allow an already heap allocated bodyPart to be added.
7. Made most of the methods of CPJNSMTPMessage virtual to allow for easier end user customization of its functionality.
PJN / 14-11-2016 1. Removed unnecessary validation of pszUsername & pszPassword parameters in CPJNSMTPConnection::ConnectESMTP. Thanks to Christopher
Craft for reporting this issue.
2. Added validation of pszUsername & pszPassword parameters in CPJNSMTPConnection::AuthLogin, CPJNSMTPConnection::AuthPlain &
CPJNSMTPConnection::AuthCramMD5 methods. Thanks to Christopher Craft for reporting this issue.
3. Improved the SAL annotations on the CPJNSMTPConnection::ConnectESMTP method.
4. Reworked CPJNSMTPBodyPart::ConvertToUTF8 to use ATL::CW2A
5. Reworked the non MFC code path of the SMTP code to now be based on a new CPJNSMTP_MFC_EXTENSIONS preprocessor values instead of the
existing CWSOCKET_MFC_EXTENSIONS preprocessor value which not only applies to the socket class
6. Optimized the usage of ATL::CT2A & ATL::CA2T throughout the code
PJN / 14-04-2017 1. Updated copyright details.
2. Updated code to compile cleanly on VC 2017
PJN / 28-04-2017 1. Updated the code to compile cleanly using /permissive-.
Copyright (c) 1998 - 2017 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
All rights reserved.
Copyright / Usage Details:
You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code.
Please note that I have been informed that C(PJN)SMTPConnection is being used to develop and send unsolicted bulk mail.
This was not the intention of the code and the author explicitly forbids use of the code for any software of this kind.
*/
//////////////// Includes /////////////////////////////////////////////////////
#include "stdafx.h"
#include "PJNSmtp.h"
#include "resource.h"
#include "PJNMD5.h"
#ifndef _WININET_
#include <wininet.h>
#pragma message("To avoid this message, please put wininet.h in your pre compiled header (usually stdafx.h)")
#endif //#ifndef _WININET_
#ifndef __ATLENC_H__
#pragma message("To avoid this message, please put atlenc.h in your pre compiled header (usually stdafx.h)")
#include <atlenc.h>
#endif //#ifndef __ATLENC_H__
//////////////// Macros / Locals //////////////////////////////////////////////
#ifdef CPJNSMTP_MFC_EXTENSIONS
#ifdef _DEBUG
#define new DEBUG_NEW
#endif //#ifdef _DEBUG
#endif //#ifdef CPJNSMTP_MFC_EXTENSIONS
#pragma comment(lib, "wsock32.lib") //Automatically link in the Winsock dll
#pragma comment(lib, "rpcrt4.lib") //Automatically link in the RPC runtime dll
#pragma comment(lib, "wininet.lib") //Automatically link in the Wininet dll
#pragma comment(lib, "Dnsapi.lib") //Automatically linke to the DNS dll
//////////////// Implementation ///////////////////////////////////////////////
CPJNSMPTBase64Encode::CPJNSMPTBase64Encode() : m_nSize(0)
{
}
void CPJNSMPTBase64Encode::Encode(_In_reads_bytes_(nSize) const BYTE* pData, _In_ int nSize, _In_ DWORD dwFlags)
{
//Tidy up any heap memory we have been using
if (m_Buf.m_pData != NULL)
m_Buf.Free();
//Calculate and allocate the buffer to store the encoded data
m_nSize = ATL::Base64EncodeGetRequiredLength(nSize, dwFlags);
if (!m_Buf.Allocate(m_nSize + 1)) //We allocate an extra byte so that we can null terminate the result
CPJNSMTPConnection::ThrowPJNSMTPException(ERROR_OUTOFMEMORY, FACILITY_WIN32);
//Finally do the encoding
ATLASSUME(m_Buf.m_pData != NULL);
if (!ATL::Base64Encode(pData, nSize, m_Buf.m_pData, &m_nSize, dwFlags))
CPJNSMTPConnection::ThrowPJNSMTPException(IDS_PJNSMTP_FAIL_BASE64_ENCODE, FACILITY_ITF);
//Null terminate the data
m_Buf.m_pData[m_nSize] = '\0';
}
void CPJNSMPTBase64Encode::Decode(_In_reads_bytes_(nSize) LPCSTR pData, _In_ int nSize)
{
//Tidy up any heap memory we have been using
if (m_Buf.m_pData != NULL)
m_Buf.Free();
//Calculate and allocate the buffer to store the encoded data
m_nSize = ATL::Base64DecodeGetRequiredLength(nSize);
if (!m_Buf.Allocate(m_nSize + 1)) //We allocate an extra byte so that we can null terminate the result
CPJNSMTPConnection::ThrowPJNSMTPException(ERROR_OUTOFMEMORY, FACILITY_WIN32);
//Finally do the encoding
ATLASSUME(m_Buf.m_pData != NULL);
if (!ATL::Base64Decode(pData, nSize, reinterpret_cast<BYTE*>(m_Buf.m_pData), &m_nSize))
CPJNSMTPConnection::ThrowPJNSMTPException(IDS_PJNSMTP_FAIL_BASE64_DECODE, FACILITY_ITF);
//Null terminate the data
m_Buf.m_pData[m_nSize] = '\0';
}
void CPJNSMPTBase64Encode::Encode(_In_z_ LPCSTR pszMessage, _In_ DWORD dwFlags)
{
Encode(reinterpret_cast<const BYTE*>(pszMessage), static_cast<int>(strlen(pszMessage)), dwFlags);
}
void CPJNSMPTBase64Encode::Decode(_In_z_ LPCSTR pszMessage)
{
Decode(pszMessage, static_cast<int>(strlen(pszMessage)));
}
CPJNSMPTQPEncode::CPJNSMPTQPEncode() : m_nSize(0)
{
}
void CPJNSMPTQPEncode::Encode(_In_reads_bytes_(nSize) const BYTE* pData, _In_ int nSize, _In_ DWORD dwFlags)
{
//Tidy up any heap memory we have been using
if (m_Buf.m_pData != NULL)
m_Buf.Free();
//Calculate and allocate the buffer to store the encoded data
m_nSize = ATL::QPEncodeGetRequiredLength(nSize);
if (!m_Buf.Allocate(m_nSize + 1)) //We allocate an extra byte so that we can null terminate the result
CPJNSMTPConnection::ThrowPJNSMTPException(ERROR_OUTOFMEMORY, FACILITY_WIN32);
//Finally do the encoding
ATLASSUME(m_Buf.m_pData != NULL);
if (!ATL::QPEncode(const_cast<BYTE*>(pData), nSize, m_Buf.m_pData, &m_nSize, dwFlags)) //ATL::QPEncode is incorrectly defined as taking a BYTE* instead of a const BYTE* for the first parameter
CPJNSMTPConnection::ThrowPJNSMTPException(IDS_PJNSMTP_FAIL_QP_ENCODE, FACILITY_ITF);
//Null terminate the data
m_Buf.m_pData[m_nSize] = '\0';
}
void CPJNSMPTQPEncode::Encode(_In_z_ LPCSTR pszMessage, _In_ DWORD dwFlags)
{
Encode(reinterpret_cast<const BYTE*>(pszMessage), static_cast<int>(strlen(pszMessage)), dwFlags);
}
CPJNSMPTQEncode::CPJNSMPTQEncode() : m_nSize(0)
{
}
void CPJNSMPTQEncode::Encode(_In_reads_bytes_(nSize) const BYTE* pData, _In_ int nSize, _In_z_ LPCSTR szCharset)
{
//Tidy up any heap memory we have been using
if (m_Buf.m_pData != NULL)
m_Buf.Free();
//Calculate and allocate the buffer to store the encoded data
m_nSize = ATL::QEncodeGetRequiredLength(nSize, ATL_MAX_ENC_CHARSET_LENGTH);
if (!m_Buf.Allocate(m_nSize + 1)) //We allocate an extra byte so that we can null terminate the result
CPJNSMTPConnection::ThrowPJNSMTPException(ERROR_OUTOFMEMORY, FACILITY_WIN32);
//Finally do the encoding
ATLASSUME(m_Buf.m_pData != NULL);
if (!ATL::QEncode(const_cast<BYTE*>(pData), nSize, m_Buf.m_pData, &m_nSize, szCharset)) //ATL::QEncode is incorrectly defined as taking a BYTE* instead of a const BYTE* for the first parameter
CPJNSMTPConnection::ThrowPJNSMTPException(IDS_PJNSMTP_FAIL_Q_ENCODE, FACILITY_ITF);
//Null terminate the data
m_Buf.m_pData[m_nSize] = '\0';
}
void CPJNSMPTQEncode::Encode(_In_z_ LPCSTR pszMessage, _In_z_ LPCSTR szCharset)
{
Encode(reinterpret_cast<const BYTE*>(pszMessage), static_cast<int>(strlen(pszMessage)), szCharset);
}
CPJNSMTPException::CPJNSMTPException(_In_ HRESULT hr, _In_ const CPJNSMTPString& sLastResponse) : m_hr(hr),
m_sLastResponse(sLastResponse)
{
}
CPJNSMTPException::CPJNSMTPException(_In_ DWORD dwError, _In_ DWORD dwFacility, _In_ const CPJNSMTPString& sLastResponse) : m_hr(MAKE_HRESULT(SEVERITY_ERROR, dwFacility, dwError)),
m_sLastResponse(sLastResponse)
{
}
#if _MSC_VER >= 1700
BOOL CPJNSMTPException::GetErrorMessage(_Out_writes_z_(nMaxError) LPTSTR lpszError, _In_ UINT nMaxError, _Out_opt_ PUINT pnHelpContext)
#else
BOOL CPJNSMTPException::GetErrorMessage(__out_ecount_z(nMaxError) LPTSTR lpszError, __in UINT nMaxError, __out_opt PUINT pnHelpContext)
#endif //#if _MSC_VER >= 1700
{
//Validate our parameters
ATLASSERT(lpszError != NULL);
ATLASSERT(nMaxError != 0);
lpszError[0] = _T('\0');
if (pnHelpContext != NULL)
*pnHelpContext = 0;
//What will be the return value from this method (assume the worst)
BOOL bSuccess = FALSE;
if (HRESULT_FACILITY(m_hr) == FACILITY_ITF)
{
//Simply load up the string from the string table
CPJNSMTPString sError;
#ifdef CPJNSMTP_MFC_EXTENSIONS
bSuccess = sError.LoadString(HRESULT_CODE(m_hr));
if (bSuccess)
Checked::tcsncpy_s(lpszError, nMaxError, sError, _TRUNCATE);
#else
TCHAR szResource[4096];
szResource[0] = _T('\0');
bSuccess = (LoadString(GetModuleHandle(NULL), HRESULT_CODE(m_hr), szResource, sizeof(szResource) / sizeof(TCHAR)) != 0);
if (bSuccess)
{
sError = szResource;
Checked::tcsncpy_s(lpszError, nMaxError, sError.c_str(), _TRUNCATE);
}
#endif //#ifdef CPJNSMTP_MFC_EXTENSIONS
}
else
{
LPTSTR lpBuffer = NULL;
DWORD dwReturn = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, m_hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
reinterpret_cast<LPTSTR>(&lpBuffer), 0, NULL);
if (dwReturn == 0)
*lpszError = _T('\0');
else
{
bSuccess = TRUE;
Checked::tcsncpy_s(lpszError, nMaxError, lpBuffer, _TRUNCATE);
LocalFree(lpBuffer);
}
}
return bSuccess;
}
#ifdef CPJNSMTP_MFC_EXTENSIONS
CPJNSMTPString CPJNSMTPException::GetErrorMessage()
{
CPJNSMTPString rVal;
LPTSTR pstrError = rVal.GetBuffer(4096);
GetErrorMessage(pstrError, 4096, NULL);
rVal.ReleaseBuffer();
return rVal;
}
#ifdef _DEBUG
void CPJNSMTPException::Dump(CDumpContext& dc) const
{
//Let the base class do its thing
CObject::Dump(dc);
dc << _T("m_hr = ") << m_hr << _T("\n");
}
#endif //#ifdef _DEBUG
#endif //#ifdef CPJNSMTP_MFC_EXTENSIONS
CPJNSMTPAddress::CPJNSMTPAddress()
{
}
CPJNSMTPAddress::CPJNSMTPAddress(_In_ const CPJNSMTPAddress& address)
{
*this = address;
}
#ifdef CPJNSMTP_MFC_EXTENSIONS
CPJNSMTPAddress::CPJNSMTPAddress(_In_z_ LPCTSTR pszAddress)
{
//The local variable which we will operate on
CPJNSMTPString sTemp(pszAddress);
sTemp.Trim();
//divide the substring into friendly names and e-mail addresses
int nMark = sTemp.Find(_T('<'));
int nMark2 = sTemp.Find(_T('>'));
if ((nMark != -1) && (nMark2 != -1) && (nMark2 > (nMark+1)))
{
m_sEmailAddress = sTemp.Mid(nMark + 1, nMark2 - nMark - 1);
m_sFriendlyName = sTemp.Left(nMark);
//Tidy up the parsed values
m_sFriendlyName.Trim();
m_sFriendlyName = RemoveQuotes(m_sFriendlyName);
m_sEmailAddress.Trim();
m_sEmailAddress = RemoveQuotes(m_sEmailAddress);
}
else
{
nMark = sTemp.Find(_T('('));
nMark2 = sTemp.Find(_T(')'));
if ((nMark != -1) && (nMark2 != -1) && (nMark2 > (nMark+1)))
{
m_sEmailAddress = sTemp.Left(nMark);
m_sFriendlyName = sTemp.Mid(nMark + 1, nMark2 - nMark - 1);
//Tidy up the parsed values
m_sFriendlyName.Trim();
m_sFriendlyName = RemoveQuotes(m_sFriendlyName);
m_sEmailAddress.Trim();
m_sEmailAddress = RemoveQuotes(m_sEmailAddress);
}
else
m_sEmailAddress = sTemp;
}
}
#else
CPJNSMTPAddress::CPJNSMTPAddress(_In_z_ LPCTSTR pszAddress)
{
//The local variable which we will operate on
CPJNSMTPString sTemp(pszAddress);
StringTrim(sTemp);
//divide the substring into friendly names and e-mail addresses
CPJNSMTPString::size_type nMark = sTemp.find(_T('<'));
CPJNSMTPString::size_type nMark2 = sTemp.find(_T('>'));
if ((nMark != CPJNSMTPString::npos) && (nMark2 != CPJNSMTPString::npos) && (nMark2 > (nMark + 1)))
{
m_sEmailAddress = sTemp.substr(nMark + 1, nMark2 - nMark - 1); //PJ TO DO: May be an off by one issue here
m_sFriendlyName = sTemp.substr(0, nMark); //PJ TO DO: May be an off by one issue here
//Tidy up the parsed values
StringTrim(m_sFriendlyName);
m_sFriendlyName = RemoveQuotes(m_sFriendlyName);