Send email (sockets)

Hello,
I want to send email in C++ using sockets:
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

#include "io.h"
#include "winsock2.h"      /* WSAGetLastError, WSAStartUp  */
#define snprintf _snprintf


static void sendmail_write(
                const int  sock,
                const char *str,
                const char *arg
            ) {
    char buf[4096];

    if (arg != NULL)
        snprintf(buf, sizeof(buf), str, arg);
    else
        snprintf(buf, sizeof(buf), str);

    send(sock, buf, strlen(buf), 0);
}

static int sendmail(
                const char *from,
                const char *to,
                const char *subject,
                const char *body,
                const char *hostname,
                const int   port
            ) {

    struct hostent *host;
    struct sockaddr_in saddr_in;
    int sock = 0;


	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
		return -1;
	}


    sock = socket(AF_INET, SOCK_STREAM, 0);
	host = gethostbyname(hostname);

	saddr_in.sin_family      = AF_INET;
	saddr_in.sin_port        = htons((u_short)port);
	saddr_in.sin_addr.s_addr = 0;

	memcpy((char*)&(saddr_in.sin_addr), host->h_addr, host->h_length);

	if (connect(sock, (struct sockaddr*)&saddr_in, sizeof(saddr_in)) == -1) {
		return -2;
	}

    sendmail_write(sock, "HELO %s\n",       from);    // greeting
    sendmail_write(sock, "MAIL FROM: %s\n", from);    // from
    sendmail_write(sock, "RCPT TO: %s\n",   to);      // to
    sendmail_write(sock, "DATA\n",          NULL);    // begin data

    // next comes mail headers
    sendmail_write(sock, "From: %s\n",      from);
    sendmail_write(sock, "To: %s\n",        to);
    sendmail_write(sock, "Subject: %s\n",   subject);

    sendmail_write(sock, "\n",              NULL);

    sendmail_write(sock, "%s\n",            body);    // data

    sendmail_write(sock, ".\n",             NULL);    // end data
    sendmail_write(sock, "QUIT\n",          NULL);    // terminate

    close(sock);

    return 0;
}


int main(int argc, char *argv[]) {

    int ret = sendmail(
        "testas@domainname.com",  // from
        "Null665@gmail.com", // to
        "Subject",
        "body",
        "smtp.google.com",
        25
    );

    if (ret != 0)
        fprintf(stderr, "Failed to send mail (code: %i).\n", ret);
    else
        fprintf(stdout, "Mail successfully sent.\n");

    return ret;
}

It prints Mail successfully sent. but I don't see the email in my inbox. Anyone knows why? (The code isn't mine; I found it on the internet)

Thanks for help!
Anyone?
Went through something like this a few weeks ago with someone on these very forums - (this looks so familiar it might be the same code)
One thing we found was that the from string - this bit here:
sendmail_write(sock, "HELO %s\n", from); // greeting won't work

if the string contains illegal characters like @ - so the string "testas@domainname.com" would be unsuitable.

So at the moment the mail isn't actually going through - you don't know that because you are not checking the replies from the server.

Try changing that line for something like
sendmail_write(sock, "HELO %s\n", " null"); // greeting and see what happens.
Last edited on
Still doesn't work. I added error checking code and it shows that send() doesn't fail. When I tried to run it on Vista, WSAStartup() failed.
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

static void sendmail_write(
    const int  sock,
    const char *str,
    const char *arg
) {
    char buf[4096];

    if (arg != NULL)
        snprintf(buf, sizeof(buf), str, arg);
    else
        snprintf(buf, sizeof(buf), str);
    cout <<"sendmail_write(): "<<buf<<endl;
    if(send(sock, buf, strlen(buf), 0)==SOCKET_ERROR)
      {
          cout <<"\t socket error!"<<endl;
      }
}

static int sendmail(
    const char *from,
    const char *to,
    const char *subject,
    const char *body,
    const char *hostname,
    const int   port
) {

    struct hostent *host;
    struct sockaddr_in saddr_in;
    int sock = 0;


    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        return -1;
    }


    sock = socket(AF_INET, SOCK_STREAM, 0);
    host = gethostbyname(hostname);

    saddr_in.sin_family      = AF_INET;
    saddr_in.sin_port        = htons((u_short)port);
    saddr_in.sin_addr.s_addr = 0;

    memcpy((char*)&(saddr_in.sin_addr), host->h_addr, host->h_length);

    if (connect(sock, (struct sockaddr*)&saddr_in, sizeof(saddr_in)) == -1) {
        return -2;
    }

    sendmail_write(sock, "HELO %s\n",       "null");    // greeting
    sendmail_write(sock, "MAIL FROM: %s\n", from);    // from
    sendmail_write(sock, "RCPT TO: %s\n",   to);      // to
    sendmail_write(sock, "DATA\n",          NULL);    // begin data

    // next comes mail headers
    sendmail_write(sock, "From: %s\n",      from);
    sendmail_write(sock, "To: %s\n",        to);
    sendmail_write(sock, "Subject: %s\n",   subject);

    sendmail_write(sock, "\n",              NULL);

    sendmail_write(sock, "%s\n",            body);    // data

    sendmail_write(sock, ".\n",             NULL);    // end data
    sendmail_write(sock, "QUIT\n",          NULL);    // terminate

    close(sock);

    return 0;
}


int main(int argc, char *argv[]) {

    int ret = sendmail(
                  "testas@domainname.com",  // from
                  "Null665@gmail.com", // to
                  "Subject",
                  "body",
                  "smtp.google.com",
                  25
              );

    if (ret != 0)
        fprintf(stderr, "Failed to send mail (code: %i).\n", ret);
    else
        fprintf(stdout, "Mail successfully sent.\n");

    return ret;
}
delete the line 'sendmail_write(sock, "HELO %s\n", "null");', this line code is not must having; socket is having IP and PORT
I very rarely see anyone use snprintf, well done!

One would not expect WSAStartup to fail. If it does, you have real system problems.
 
    sock = socket(AF_INET, SOCK_STREAM, 0);
should be:
 
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
The TCP stack as of XP is picky about this.

Also, on Windows:
 
    closesocket(sock);
should be:
 
    close(sock);
A socket isn't a standard file descriptor on Windows.

Although your problem isn't here, this is technically incorrect:
 
    if(send(sock, buf, strlen(buf), 0)==SOCKET_ERROR)
send returns the number of bytes sent, or -1 if it fails. If the return value isn't -1 and is less than strlen(buf), you have to loop until the entire buffer has been send.

I haven't the time to check your SMTP conversation now, I'll take a look this evening if I have time.

One thing I'd mention is to check your end of line characters. I looked after an app that worked for the best part of 10 years connecting to sendmail until one customer pointed it to Exchange which expected different (actually the correct) eol characters. You'll need to check the RFC to be certain as I can't remember what was what.

EDIT: I just noticed you aren't reading replies from the server. How do you know it's happy with you if you don't?
Last edited on
Null wrote:
When I tried to run it on Vista, WSAStartup() failed.
kbw wrote:
One would not expect WSAStartup to fail. If it does, you have real system problems.


==================================================================

NOTE
I am going from memory here, you are advised to look this up before doing it.
This will remove any third party Layered Service Providers (LSP). Any that are installed would prbably need to be reinstalled.
==================================================================

If you want you could try this:
Find command prompt in the start menu, right click and select Run as Administrator.(put in your admin details)
At the command prompt, type: "netsh winsock reset" and enter.
Reboot your computer and try see if WSAStartup() is successful.

Good grief! I hate Vista.

It's no wonder that no one in the industry I work in use it.
Last edited on
@Grey Wolf: Your suggestion worked, thanks,

Also, on Windows:
closesocket(sock);
should be:
close(sock);

Do you mean
Also, on Windows:
close(sock);
should be:
closesocket(sock);

?

I hate Vista.
Me too. I think I'm going to reinstall XP.

EDIT: OK, I'm back on Windows XP but now connect() function fails. What could go wrong now? And is there a way to get a more detailed error information?

Last edited on
I've never used Vista so I can't comment on that, (I'm now on Windows 7) -
This works for me (using MSVC 2008)


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
#include <windows.h> 
#include <stdio.h>
#include <io.h>
//#include <winsock2.h>  //on MSVC2008 - windows.h already includes winsock stuff    /* WSAGetLastError, WSAStartUp  */
#define snprintf _snprintf


static void sendmail_write(
                const int  sock,
                const char *str,
                const char *arg
            ) {
    char buf[4096];

    if (arg != NULL)
        snprintf(buf, sizeof(buf), str, arg);
    else
        snprintf(buf, sizeof(buf), str);

    send(sock, buf, strlen(buf), 0);
}

static int sendmail(
                const char *from,
                const char *to,
                const char *subject,
                const char *body,
                const char *hostname,
                const int   port
            ) {

    struct hostent *host;
    struct sockaddr_in saddr_in;
    int sock = 0;


    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        return -1;
    }


    sock = socket(AF_INET, SOCK_STREAM, 0);
    host = gethostbyname(hostname);

    saddr_in.sin_family      = AF_INET;
    saddr_in.sin_port        = htons((u_short)port);
    saddr_in.sin_addr.s_addr = 0;

    memcpy((char*)&(saddr_in.sin_addr), host->h_addr, host->h_length);

    if (connect(sock, (struct sockaddr*)&saddr_in, sizeof(saddr_in)) == -1) {
        return -2;
    }

   
    
    sendmail_write(sock, "HELO %s\n",       "Testname");    // greeting****************
    
    sendmail_write(sock, "MAIL FROM: %s\n", from);    // from
    
    sendmail_write(sock, "RCPT TO: %s\n",   to);      // to    
   
    sendmail_write(sock, "DATA\n",          NULL);    // begin data

    // next comes mail headers
    sendmail_write(sock, "From: %s\n",      from);
    
    
    sendmail_write(sock, "To: %s\n",        to);
    
    
    sendmail_write(sock, "Subject: %s\n",   subject);

    sendmail_write(sock, "\n",              NULL);

    sendmail_write(sock, "%s\n",            body);    // data

    sendmail_write(sock, ".\n",             NULL);    // end data
    sendmail_write(sock, "QUIT\n",          NULL);    // terminate

    closesocket(sock);//*******************************

    return 0;
}


int main(int argc, char *argv[]) {

    int ret = sendmail(
        "firstname.lastname@domain.com",  // from - put an email address here
        "firstname.lastname@domain.com", // to - put an email address here
        "Subject",
        "body",
        "smtp.blueyonder.co.uk",//this is my ISP -use your own
        25
    );

    if (ret != 0)
        fprintf(stderr, "Failed to send mail (code: %i).\n", ret);
    else
        fprintf(stdout, "Mail successfully sent.\n");

    return ret;
}
kbw wrote:
EDIT: I just noticed you aren't reading replies from the server. How do you know it's happy with you if you don't?

I modified sendmail_write function to receive replies from server and this is what I get:

220 mx.google.com ESMTP b52sm1293073eei.19
250 mx.google.com at your service
530 5.7.0 Must issue a STARTTLS command first. b52sm1293073eei.19
530 5.7.0 Must issue a STARTTLS command first. b52sm1293073eei.19
530 5.7.0 Must issue a STARTTLS command first. b52sm1293073eei.19
502 5.5.1 Unrecognized command. b52sm1293073eei.19
502 5.5.1 Unrecognized command. b52sm1293073eei.19
502 5.5.1 Unrecognized command. b52sm1293073eei.19
502 5.5.1 Unrecognized command. b52sm1293073eei.19
502 5.5.1 Unrecognized command. b52sm1293073eei.19
554 5.7.0 Too Many Unauthenticated commands. b52sm1293073eei.19

It tells me to use STARTTLS command, so I modified my code to do so.

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
static void sendmail_write(const int  sock,const char *str,const char *arg)
 {
    char buf[4096];

    if (arg != NULL)
        snprintf(buf, sizeof(buf), str, arg);
    else
        snprintf(buf, sizeof(buf), str);

    send(sock, buf, strlen(buf), 0);

// read a reply from server
    char outbuf[1024];
    int len=recv(sock,outbuf,1024,0);
    outbuf[len]='\0';
    cout <<outbuf;


}

static int sendmail(
                const char *from,
                const char *to,
                const char *subject,
                const char *body,
                const char *hostname,
                const int   port
            ) {

    struct hostent *host;
    struct sockaddr_in saddr_in;
    int sock = 0;


    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        return -1;
    }


    sock = socket(AF_INET, SOCK_STREAM, 0);
    host = gethostbyname(hostname);

    saddr_in.sin_family      = AF_INET;
    saddr_in.sin_port        = htons((u_short)port);
    saddr_in.sin_addr.s_addr = 0;

    memcpy((char*)&(saddr_in.sin_addr), host->h_addr, host->h_length);

    if (connect(sock, (struct sockaddr*)&saddr_in, sizeof(saddr_in)) == -1) {
        return -2;
    }



    sendmail_write(sock, "EHLO %s\n",       "Testname");  // Should I use HELO or EHLO?

    sendmail_write(sock, "STARTTLS\n",""); // <----- starting TLS?


    sendmail_write(sock, "MAIL FROM: %s\n", from);    // from
    sendmail_write(sock, "RCPT TO: %s\n",   to);      // to
    sendmail_write(sock, "DATA\n",          NULL);    // begin data
    sendmail_write(sock, "From: %s\n",      from);
    sendmail_write(sock, "To: %s\n",        to);
    sendmail_write(sock, "Subject: %s\n",   subject);
    sendmail_write(sock, "\n",              NULL);
    sendmail_write(sock, "%s\n",            body);    // data
    sendmail_write(sock, ".\n",             NULL);    // end data
    sendmail_write(sock, "QUIT\n",          NULL);    // terminate

    closesocket(sock);

    return 0;
}


int main(int argc, char *argv[]) {

    int ret = sendmail(

        "firstname.lastname@domain.com",  // from - put an email address here
        "Null665@gmail.com", // to - put an email address here
        "subject_sendmail",
        "body_text",
        "smtp.gmail.com",
        25
    );

    if (ret != 0)
        fprintf(stderr, "Failed to send mail (code: %i).\n", ret);
    else
        fprintf(stdout, "Mail successfully sent.\n");

    return ret;
}

This is the response from server:
220 mx.google.com ESMTP x54sm1306814eeh.5
250-mx.google.com at your service, [213.130.222.250]
250-SIZE 35651584
250-8BITMIME
250-STARTTLS
250 ENHANCEDSTATUSCODES
220 2.0.0 Ready to start TLS

What should I do next?
Ah, just did a quick google - this TLS thing is all about secure connection (SSL) - looks like the google mail server is running a secure connection.
I'll need to read up some more ...
I'm reading this site here:
http://xml.resource.org/public/rfc/html/rfc2487.html
gmail closes the connection whenever I try to type the sender address:


connecting to 74.125.79.109 ...
Connection established
220 mx.google.com ESMTP b52sm3292725eei.19

EHLO
250-mx.google.com at your service, [83.178.83.189]
250-SIZE 35651584
250-8BITMIME
250-STARTTLS
250 ENHANCEDSTATUSCODES

STARTTLS
220 2.0.0 Ready to start TLS

MAIL FROM:
Session closed

What could be a reason for this?
See Pages 30 and 31 of http://www.ietf.org/rfc/rfc2246.txt
I found a simpler solution - I decided to use another ISP that doesn't require TLS authentication.

Thanks for your help!
Why don't you use a library?
Last edited on
Topic archived. No new replies allowed.