Hello and good evening to you,
This topic has been sort of a trouble to me and to many, suppose i want to send EMail in a C++ program to use smtp and StartTLS , what do i do, i culled a simple source code from google and i saw this code from here
http://www.drdobbs.com/sending-e-mail-using-smtp-and-winsock/184416591
now i want to use google mail and it uses authentication for smtp and also startTLS how do i do this
the sourcecode i saw looks like this
#pragma comment(lib, "wsock32.lib")
#include <windows.h>
#include "MailMessage.h"
int main(int argc, char **argv)
{
MailMessage mail("A Sender",
"someone#someplace.com",
"mail.someplace.com");
mail.To("A Recipient",
"you#yourplace.com");
mail.Subject("Sample message");
mail.Body("Plain text body",
"<HTML><BODY>\r\n"
" <H2>HTML Body</H2>\r\n"
"</BODY></HTML>""\r\n");
mail.Attach("C:\\Attach.txt");
const char *result =
mail.Send().data();
if (result[0] == '\0')
result = "Success";
MessageBox(NULL, result, "Result",
MB_ICONINFORMATION|MB_OK);
return 0;
}
After connecting to the server and issuing a EHLO (not HELO) command, if the server's reply includes the STARTTLS capability then you can issue a STARTTLS command at any time to create a secure session with the server. Upon receiving a successful STARTTLS reply, you need to send and complete an SSL/TLS handshake. Once the session has been created, you can continue sending your SMTP commands and receiving SMTP replies, starting with a new EHLO command (as the server's capabilities can change after the connection is secured). You have to encrypt your commands and decrypt the replies as you go. The communication would look like this (this example assumes an Application-Specific password has been configured in GMail if two-step verification is enabled):
S: 220 smtp.gmail.com ESMTP dg12sm55710335pac.47 - gsmtp
C: EHLO <hostname>
S: 250-smtp.gmail.com at your service, [<ip address>]
S: 250-SIZE 35882577
S: 250-8BITMIME
S: 250-STARTTLS
S: 250-ENHANCEDSTATUSCODES
S: 250-PIPELINING
S: 250-CHUNKING
S: 250 SMTPUTF8
C: STARTTLS
S: 220 2.0.0 Ready to start TLS
C/S: (Exchange SSL/TLS handshake)
C/S: (Everything from here on is now encrypted)
C: EHLO <hostname>
S: 250-smtp.gmail.com at your service, [<ip address>]
S: 250-SIZE 35882577
S: 250-8BITMIME
S: 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
S: 250-ENHANCEDSTATUSCODES
S: 250-PIPELINING
S: 250-CHUNKING
S: 250 SMTPUTF8
C: AUTH LOGIN
S: 334 VXNlcm5hbWU6
C: (Send base64 encoded username)
S: 334 UGFzc3dvcmQ6
C: (Send base64 encoded password)
S: 235 2.7.0 Accepted
C: (Send email as needed)
C: QUIT
S: 221 2.0.0 closing connection m1sm91929700pfi.27 - gsmtp
Now, how you actually handle the encryption is up to you. You can use a library like OpenSSL, or you can use Microsoft's Crypto/SChannel API. There are plenty of online tutorials and books on how to use them with sockets.
Related
I'm using Mailgun through my local installation of Mautic. It used to connect correctly. Today however I got this error message: Unable to connect with TLS encryption Log data: ++ Starting Swift_SmtpTransport << 220-node6237.myfcloud.com ESMTP Exim 4.95 #2 Tue, 12 Apr 2022 13:38:14 +0000 220-We do not authorize the use of this system to transport unsolicited, 220 and/or bulk e-mail. >> EHLO dashboard.nsking.ee << 250-node6237.myfcloud.com Hello dashboard.nsking.ee [194.233.160.33] 250-SIZE 52428800 250-8BITMIME 250-PIPELINING 250-PIPE_CONNECT 250-AUTH PLAIN LOGIN 250-STARTTLS 250 HELP >> STARTTLS << 220 TLS go ahead !! Unable to connect with TLS encryption (code: 0) ++ Starting Swift_SmtpTransport << 220-node6237.myfcloud.com ESMTP Exim 4.95 #2 Tue, 12 Apr 2022 13:38:14 +0000 220-We do not authorize the use of this system to transport unsolicited, 220 and/or bulk e-mail. >> EHLO dashboard.nsking.ee << 250-node6237.myfcloud.com Hello dashboard.nsking.ee [194.233.160.33] 250-SIZE 52428800 250-8BITMIME 250-PIPELINING 250-PIPE_CONNECT 250-AUTH PLAIN LOGIN 250-STARTTLS 250 HELP >> STARTTLS << 220 TLS go ahead !! Unable to connect with TLS encryption (code: 0)
What is the cause of it? Keep in mind, nothing has changed in our installation except the server name and the IP.
I tried to change to SSL and I got this error:
Connection could not be established with host smtp.mailgun.org :stream_socket_client(): Peer certificate CN=node6237.myfcloud.com' did not match expected CN=smtp.mailgun.org' Log data: ++ Starting Swift_SmtpTransport !! Connection could not be established with host smtp.mailgun.org :stream_socket_client(): Peer certificate CN=node6237.myfcloud.com' did not match expected CN=smtp.mailgun.org' (code: 0)
++ Starting Swift_SmtpTransport !! Connection could not be established with host smtp.mailgun.org :stream_socket_client(): Peer certificate CN=node6237.myfcloud.com' did not match expected CN=smtp.mailgun.org' (code: 0)
I'm running a java app in JBoss 6.4.0 in an Amazon Web Services red hat 8 EC2 instance.
When my app tries to send an email via javax.mail I'm getting an error "Could not convert socket to TLS".
I then coded up the AmazonSESSample.java sample program and tried it. I ran it in my EC2 instance outside JBoss and it ran successfully. (The AmazonSESSample program can be found here: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/examples-send-using-smtp.html)
Then I commented out the email code in my java app, and replaced it with the code in AmazonSESSample.java. When I run my java app with the AmazonSESSample code in JBoss I get the same error: "Could not convert socket to TLS". So the AmazonSESSample works fine outside JBoss, and gives an error when running inside JBoss.
Here is the AmazonSESSample code in my app. Can somebody help me fix the "Could not convert socket to TLS" error?:
public class AmazonSESSample {
private static final Logger logger = LogManager.getFormatterLogger("AmazonSESSample");
// Replace sender#example.com with your "From" address.
// This address must be verified.
static final String FROM = "email1#gmail.com";
static final String FROMNAME = "Steve";
// Replace recipient#example.com with a "To" address. If your account
// is still in the sandbox, this address must be verified.
static final String TO = "email2#gmail.com";
// Replace smtp_username with your Amazon SES SMTP user name.
static final String SMTP_USERNAME = "thisIsNotActualghijikl";
// Replace smtp_password with your Amazon SES SMTP password.
static final String SMTP_PASSWORD = "abcdefThisIsNotActual";
// Amazon SES SMTP host name. This example uses the US West (Oregon) region.
// See https://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html#region-endpoints
// for more information.
static final String HOST = "email-smtp.us-east-2.amazonaws.com";
// The port you will connect to on the Amazon SES SMTP endpoint.
static final int PORT = 587;
static final String SUBJECT = "Amazon SES test (SMTP interface accessed using Java)";
static final String BODY = String.join(
System.getProperty("line.separator"),
"<h1>Amazon SES SMTP Email Test</h1>",
"<p>This email was sent with Amazon SES using the ",
"<a href='https://github.com/javaee/javamail'>Javamail Package</a>",
" for <a href='https://www.java.com'>Java</a>."
);
public int sendEmail(DisplayEmailMessage emailMessage) throws UnsupportedEncodingException, MessagingException {
// Create a Properties object to contain connection configuration information.
Properties props = System.getProperties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.port", PORT);
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth", "true");
// Create a Session object to represent a mail session with the specified properties.
Session session = Session.getDefaultInstance(props);
// Create a message with the specified information.
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(FROM, FROMNAME));
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(TO));
msg.setSubject(SUBJECT);
msg.setContent(BODY, "text/html");
// Create a transport.
Transport transport = session.getTransport();
// Send the message.
try {
System.out.println("Sending...");
// Connect to Amazon SES using the SMTP username and password you specified above.
transport.connect(HOST, SMTP_USERNAME, SMTP_PASSWORD);
// Send the email.
transport.sendMessage(msg, msg.getAllRecipients());
System.out.println("Email sent!");
}
catch (Exception ex) {
System.out.println("The email was not sent.");
System.out.println("Error message: " + ex.getMessage());
}
finally {
// Close and terminate the connection.
transport.close();
}
return 0;
}
}
Here is the javamail debug output:
DEBUG: setDebug: JavaMail version 1.4.5.redhat-2
Sending email to 123#gmail.com
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc]
Starting to connect at Sun Dec 26 13:14:23 UTC 2021 to email 123#gmail.com
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "smtp.dreamhost.com", port 587, isSSL false
220 pdx1-sub0-mail-a290.dreamhost.com ESMTP
DEBUG SMTP: connected to host "smtp.dreamhost.com", port: 587
EHLO ip-172-31-29-30.us-east-2.compute.internal
250-pdx1-sub0-mail-a290.dreamhost.com
250-PIPELINING
250-SIZE 40960000
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 CHUNKING
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "SIZE", arg "40960000"
DEBUG SMTP: Found extension "ETRN", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "AUTH=PLAIN", arg "LOGIN"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
STARTTLS
220 2.0.0 Ready to start TLS
MessagingException
javax.mail.MessagingException: Could not convert socket to TLS
I fixed this by upgrading my JBoss to 7.4.0.
Domain is fully verified but sometimes we did get FROM 0101016efadf82da-b7e07022-37ba-4cae-aa6c-780052992485-000000#us-west-2.amazonses.com instead of using FROM from our domain this is log can you show me what could be possible the reason ?
<< 220 email-smtp.amazonaws.com ESMTP SimpleEmailService-d-XTDLI25GD
>> EHLO [IP]
<< 250-email-smtp.amazonaws.com
250-8BITMIME
250-SIZE 10485760
250-STARTTLS
250-AUTH PLAIN LOGIN
250 Ok
>> STARTTLS
<< 220 Ready to start TLS
>> EHLO [IP]
<< 250-email-smtp.amazonaws.com
250-8BITMIME
250-SIZE 10485760
250-STARTTLS
250-AUTH PLAIN LOGIN
250 Ok
>> AUTH LOGIN
<< 334 val
>> val
<< 334 val
>> Qk8=
<< 235 Authentication successful.
++ Swift_SmtpTransport started
>> MAIL FROM:<12345#example.com>
<< 250 Ok
>> RCPT TO:<500500500#msg.fi.google.com>
<< 250 Ok
>> DATA
<< 354 End data with <CR><LF>.<CR><LF>
>>
.
<< 250 Ok
First to understand, there are two things in SMTP:
Mailfrom (Envelope From): It's a SMTP command
From header (thats something you see in Outlook)
SES always changes Mailfrom address to message-id#amazonses.com or messageid#us-west-2.amazonses.com (if region used other than us-east-1).
SES does that so you can always pass in SPF. SPF check happens on mailfrom domain which is now us-west-2.amazonses.com and Amazon publishes the TXT/SPF record for it so you don't need to configure it your domain.
AWS SES provides an option to use custom mail from where you can use your own mailfrom but in this case you would need to publish a TXT record so SPF can be passed.
https://docs.aws.amazon.com/ses/latest/DeveloperGuide/mail-from.html
Generally, you don't see Mailfrom in outlook or any webmail. The reason you're seeing it because in your telnet test, you're not adding from header. Try below test: (Add DATA command after "rcpt to" and add below line)
>> MAIL FROM:<12345#example.com>
<< 250 Ok
>> RCPT TO:<500500500#msg.fi.google.com>
Data
From: 12345#example.com
To: 500500500#msg.fi.google.com
Subject: Test
.
Once you add the From header, you should be able to see correct address in outlook or webmail.
I want to build an stmp client using c++ for learning purposes.
After I managed to implement the initial connection + auth login I am stuck on sending the message after using the data command.
Here is my code
void sendmail()
{
write_command("MAIL FROM: <foo#bar.de>");
write_command("RCPT TO: <bar.foo#baz.de>");
write_command("DATA");
write_command("Subject: testmail"); // HANGS here after data command
write_command("BlaBlub");
write_command(" ");
write_command(".");
write_command("QUIT");
}
void write_command(std::string command)
{
ssize_t n;
empty_buffer();
command += '\r';
command += '\n';
char command_buffer[255];
strcpy(command_buffer, command.c_str());
n = write(sockfd,command_buffer,strlen(command_buffer));
if (n < 0){
error("ERROR writing to socket");
}
n = read_to_buffer();
if (n < 0) {
error("ERROR reading from socket");
}
printf("%s\n",this->buffer);
}
I'm using smtp.mailtrap.io on port 25.
Here is a gist with the full class https://gist.github.com/xhallix/7f2d87a8b2eab4953d161059c2482b37
Here is the server output
Starting smpt client
220 mailtrap.io ESMTP ready
250-mailtrap.io
250-SIZE 5242880
250-PIPELINING
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-AUTH PLAIN LOGIN CRAM-MD5
250 STARTTLS
334 VXNlcm5hbWU6
334 UGFzc3dvcmQ6
235 2.0.0 OK
250 2.1.0 Ok
250 2.1.0 Ok
354 Go ahead
(HANGS HERE)
Thanks for helping me out
DATA command expects the whole mail message, as shown here. The write_command() sends a message by lines and expects response after each line. Since the server returns the response once the mail message is finished (after empty line and dot), it stays in the hanging mode after the first message line. This code snippet can be helpful for your case.
BTW, you should put an empty line between the mail header and body, which I guess is after the subject line. Also, it might happen that the server rejects the message without the From and To headers.
I am trying to send email using ASP.NET Core, MailKit and Amazon SES:
using (SmtpClient client = new SmtpClient(new ProtocolLogger("smtp.log"))) {
client.Connect("email-smtp.us-east-1.amazonaws.com", 587, SecureSocketOptions.StartTls);
client.Authenticate("myusername", "mypassword");
await client.SendAsync(message);
client.Disconnect(true);
}
I keep getting the error "The remote certificate is invalid according to the validation procedure.".
And the log file shows:
Connected to smtp://email-smtp.us-east-1.amazonaws.com:587/?starttls=always
S: 220 email-smtp.amazonaws.com ESMTP SimpleEmailService-1737464811 qt5bXhIgVseJaHPspjp4
C: EHLO [127.0.0.1]
S: 250-email-smtp.amazonaws.com
S: 250-8BITMIME
S: 250-SIZE 10485760
S: 250-STARTTLS
S: 250-AUTH PLAIN LOGIN
S: 250 Ok
C: STARTTLS
S: 220 Ready to start TLS
What am I missing?
You need to provide your own client.ServerCertificateValidationCallback method to verify the server certificate. It can be as simple as always returning true or it can check the fingerprint against a known fingerprint for the server or any number of other possibilities.
For more information, see http://www.mimekit.org/docs/html/P_MailKit_MailService_ServerCertificateValidationCallback.htm