By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,921 Members | 1,442 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,921 IT Pros & Developers. It's quick & easy.

smtp coding problem

P: n/a
hi, i have this code which is part of a main program, to email from
within the program a log file:

int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300
int bytes_sent; /* Sock FD */
int err;
struct hostent *host; /* info from gethostbyname */
struct sockaddr_in dest_addr; /* Host Address */
char line[1000];
char *Rec_Buf = (char*) malloc(bufsize+1);
smtpfile=fopen(SMTPLog,"a+");
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fputs("WSAStartup failed",smtpfile);
WSACleanup();
return -1;
}
if ( (host=gethostbyname(mailserver)) == NULL) {
perror("gethostbyname");
exit(1);
}
memset(&dest_addr,0,sizeof(dest_addr));
memcpy(&(dest_addr.sin_addr),host->h_addr,host->h_length);

/* Prepare dest_addr */
dest_addr.sin_family= host->h_addrtype; /* AF_INET from
gethostbyname */
dest_addr.sin_port= htons(25); /* PORT defined above */

/* Get socket */

if ((sockfd=socket(AF_INET,SOCK_STREAM,0)) < 0) {
perror("socket");
exit(1);
}
/* Connect !*/
fputs("Connecting....\n",smtpfile);

if (connect(sockfd, (struct sockaddr
*)&dest_addr,sizeof(dest_addr)) == -1){
perror("connect");
exit(1);
}
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"helo me.somepalace.com\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"MAIL FROM:<");
strncat(line,emailfrom,strlen(emailfrom));
strncat(line,">\n",3);
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"RCPT TO:<");
strncat(line,emailto,strlen(emailto));
strncat(line,">\n",3);
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"DATA\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
sleep(waittime);
strcpy(line,"To:");
strcat(line,emailto);
strcat(line,"\n");
strcat(line,"From:");
strcat(line,emailfrom);
strcat(line,"\n");
strcat(line,"Subject:");
strcat(line,emailsubject);
strcat(line,"\n");
strcat(line,emailmessage);
strcat(line,"\r\n.\r\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"quit\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
fclose(smtpfile);
#ifdef WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif
}

however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....

any help is appreciated.

Mar 7 '06 #1
Share this Question
Share on Google+
11 Replies


P: n/a
za****@gmail.com wrote:
hi, i have this code which is part of a main program, to email from
within the program a log file:
Your question as well as your code are off-topic in c.l.c. Try to find
a group that deals with mail protocols (I'd tell you which one/s/ but I
don't know).

Still, some remarks on what I see below:

1. Your code is hard to read. Better use of spacing would help a lot.
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300
2. Macros are conventionally all-caps (unlike types and variables).
int bytes_sent; /* Sock FD */
int err;
struct hostent *host; /* info from gethostbyname */
struct sockaddr_in dest_addr; /* Host Address */
char line[1000];
char *Rec_Buf = (char*) malloc(bufsize+1);
3. Don't cast return value of malloc(). It may hide error of not
including stdlib.h.

There's probably more, but it's hard to read, so I quit.

<snip loads of off-topic code>
however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....


See the the top comment.

--
BR, Vladimir

Mar 7 '06 #2

P: n/a
za****@gmail.com wrote:
hi, i have this code which is part of a main program, to email from
within the program a log file:
<snip>
#ifdef WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif
}

however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....


Sockets, tls, ssl and the like are not part of standard C so you will
have to ask on groups dedicated to your implementations or socket
programming (if there are any). From the looks of it you are supporting
both Windows and POSIX systems, so you might have to ask on a couple of
groups. I would suggest comp.unix.programmer and one of the microsoft
groups as starting points, although you should check their FAQs and read
a few days posts first. Had you done that here you might have realised
that your question was not topical.
--
Flash Gordon, living in interesting times.
Web site - http://home.flash-gordon.me.uk/
comp.lang.c posting guidelines and intro:
http://clc-wiki.net/wiki/Intro_to_clc
Mar 7 '06 #3

P: n/a
"Vladimir S. Oka" <no****@btopenworld.com> writes:
za****@gmail.com wrote:

[...]
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300


2. Macros are conventionally all-caps (unlike types and variables).


But FILE, defined in <stdio.h>, is an exception to this.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Mar 7 '06 #4

P: n/a
On Tue, 07 Mar 2006 20:49:03 GMT, Keith Thompson <ks***@mib.org> wrote
in comp.lang.c:
"Vladimir S. Oka" <no****@btopenworld.com> writes:
za****@gmail.com wrote:

[...]
int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300


2. Macros are conventionally all-caps (unlike types and variables).


But FILE, defined in <stdio.h>, is an exception to this.


Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Mar 8 '06 #5

P: n/a
Jack Klein <ja*******@spamcop.net> writes:
Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.


In the locally installed glibc it appears to just be a typedef:
typedef struct _IO_FILE FILE;
There's a lot of conditional inclusion nonsense nearby so I might
be missing a macro definition.

You appear to be equating macros and typedefs. I don't
understand that.
--
"What is appropriate for the master is not appropriate for the novice.
You must understand the Tao before transcending structure."
--The Tao of Programming
Mar 8 '06 #6

P: n/a
Jack Klein <ja*******@spamcop.net> writes:
On Tue, 07 Mar 2006 20:49:03 GMT, Keith Thompson <ks***@mib.org> wrote
in comp.lang.c:
"Vladimir S. Oka" <no****@btopenworld.com> writes:
> za****@gmail.com wrote:

[...]
>> int MailIt (char *mailserver, char *emailto, char *emailfrom,
>> char *emailsubject, char *emailmessage) {
>> SOCKET sockfd;
>> WSADATA wsaData;
>> FILE *smtpfile;
>>
>> #define bufsize 300
>
> 2. Macros are conventionally all-caps (unlike types and variables).


But FILE, defined in <stdio.h>, is an exception to this.


Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.


Typedefs are not macros.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Mar 8 '06 #7

P: n/a
In article <b0********************************@4ax.com>,
Jack Klein <ja*******@spamcop.net> wrote:
Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.


SGI IRIX 6.2 and SGI IRIX 6.5 have it as a typedef.
--
If you lie to the compiler, it will get its revenge. -- Henry Spencer
Mar 8 '06 #8

P: n/a
Keith Thompson <ks***@mib.org> writes:
Jack Klein <ja*******@spamcop.net> writes:
On Tue, 07 Mar 2006 20:49:03 GMT, Keith Thompson <ks***@mib.org> wrote
in comp.lang.c:
"Vladimir S. Oka" <no****@btopenworld.com> writes:
> za****@gmail.com wrote:
[...]
>> int MailIt (char *mailserver, char *emailto, char *emailfrom,
>> char *emailsubject, char *emailmessage) {
>> SOCKET sockfd;
>> WSADATA wsaData;
>> FILE *smtpfile;
>>
>> #define bufsize 300
>
> 2. Macros are conventionally all-caps (unlike types and variables).

But FILE, defined in <stdio.h>, is an exception to this.


Just curious, have you ever seen a <stdio.h> where FILE is not a macro
(i.e., a typedef?). I don't think I ever have.


Typedefs are not macros.


Or did you mean "a typedef" to correspond to "not a macro" rather than
to "a macro"? If so, the question at least makes sense, but FILE is
usually a typedef (not a macro) in all the <stdio.h> implementations
I've seen.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Mar 8 '06 #9

P: n/a
Keith Thompson <ks***@mib.org> writes:
[...]
Or did you mean "a typedef" to correspond to "not a macro" rather than
to "a macro"? If so, the question at least makes sense, but FILE is
usually a typedef (not a macro) in all the <stdio.h> implementations
I've seen.


That last sentence ("usually ... all") was a victim of careless
editing and insufficient proofreading.

I think that FILE is a typedef (not a macro) in all the <stdio.h>
implementations I've seen. I know it's a typedef in all the <stdio.h>
implementations I have easy access to at the moment (Linux, Cygwin,
Solaris, AIX, OSF); the fact that those are all Unix-like systems may
imply some bias.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Mar 8 '06 #10

P: n/a
On 2006-03-08, Keith Thompson <ks***@mib.org> wrote:
Keith Thompson <ks***@mib.org> writes:
[...]
Or did you mean "a typedef" to correspond to "not a macro" rather than
to "a macro"? If so, the question at least makes sense, but FILE is
usually a typedef (not a macro) in all the <stdio.h> implementations
I've seen.


That last sentence ("usually ... all") was a victim of careless
editing and insufficient proofreading.

I think that FILE is a typedef (not a macro) in all the <stdio.h>
implementations I've seen. I know it's a typedef in all the <stdio.h>
implementations I have easy access to at the moment (Linux, Cygwin,
Solaris, AIX, OSF); the fact that those are all Unix-like systems may
imply some bias.


Unix V7's stdio.h contains:

# ifndef FILE
extern struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
char _flag;
char _file;
} _iob[_NFILE];
# endif
#define FILE struct _iobuf

Like many things in modern C implementations, stdio was, of course,
invented for v7. [v6 had a bizarre precursor library, with no FILE's -
the user-visible API used file descriptors despite the fact that the
library maintained buffering etc.]
Mar 8 '06 #11

P: n/a
On 7 Mar 2006 06:48:53 -0800, "za****@gmail.com" <za****@gmail.com>
wrote:

#if mostly_offtopic but see some points below
hi, i have this code which is part of a main program, to email from
within the program a log file:

int MailIt (char *mailserver, char *emailto, char *emailfrom,
char *emailsubject, char *emailmessage) {
SOCKET sockfd;
WSADATA wsaData;
FILE *smtpfile;

#define bufsize 300
int bytes_sent; /* Sock FD */
int err;
struct hostent *host; /* info from gethostbyname */
struct sockaddr_in dest_addr; /* Host Address */
char line[1000];
char *Rec_Buf = (char*) malloc(bufsize+1);
It's odd to make 1000 bytes automatic but 300+1 dynamic (heap). Legal,
but odd. Unless there's a reason for the difference, be consistent.
smtpfile=fopen(SMTPLog,"a+");
Your code doesn't need + (update), and you should check the result of
fopen for a null pointer (indicating failure) before using it.
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fputs("WSAStartup failed",smtpfile);
WSACleanup();
return -1;
}
As you conditionalize Windows/Unix below, this should be Win-only.
if ( (host=gethostbyname(mailserver)) == NULL) {
perror("gethostbyname");
exit(1);
}
memset(&dest_addr,0,sizeof(dest_addr));
memcpy(&(dest_addr.sin_addr),host->h_addr,host->h_length);

/* Prepare dest_addr */
dest_addr.sin_family= host->h_addrtype; /* AF_INET from
gethostbyname */
dest_addr.sin_port= htons(25); /* PORT defined above */

/* Get socket */

if ((sockfd=socket(AF_INET,SOCK_STREAM,0)) < 0) {
perror("socket");
exit(1);
}
This shouldn't work for Windows where SOCKET is a handle -- and the
part above would work _only_ for Windows. Should test ==
INVALID_SOCKET, which you can easily make work on Unix also.
/* Connect !*/
fputs("Connecting....\n",smtpfile);

if (connect(sockfd, (struct sockaddr
*)&dest_addr,sizeof(dest_addr)) == -1){
perror("connect");
exit(1);
}
Your other checks are for SOCKET_ERROR; this is inconsistent.
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
There's no point in sleep'ing before recv'ing on a blocking socket.
The return from recv, as other POSIX I/O calls, can be negative, in
which case the array indexing is invalid. To be really picky, you
shouldn't assume a "message" from the other end of a TCP connection,
here the server banner, will always be received by one recv() call.
However, you have more serious problems to deal with.
strcpy(line,"helo me.somepalace.com\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
SMTP commands (and responses), like most(?) other textual Internet
protocols, must end with CR LF. \n is a single character, almost
certainly (not absolutely) LF, but can't be two. For I/O to a text
stream using <stdio.h>, \n will be translated to (and from) the
system's line delimiter which on _some_ systems like Windows is CR LF,
but even there no such thing happens for socket routines.
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"MAIL FROM:<");
strncat(line,emailfrom,strlen(emailfrom));
This will always terminate at the count rather than the null, and thus
not correctly terminate the string you're building. At best, if the
value you build here is shorter than the value you did above, you just
get a mixed wrong value; at worst, if your next line runs off into
uninitialized memory you officially get Undefined Behavior which could
in theory be anything up to nasal demons, and in practice will often
be a crash or garbage data.
strncat(line,">\n",3);
This works if the above line didn't leave an invalid string, but both
the previous one and this one could more easily use strcat() no n.
Or you could replace all three lines by
sprintf (line, "MAIL FROM <%s>\r\n", emailfrom);
(Note added CR per above. Or even better \x0D\x0A, although for a
seriously non-ASCII machine you need many other changes as well.)

But either of these ways is vulnerable to overflow if the supplied
string is too long; at simplest you could use
sprintf (line, "MAIL FROM <%.120s>\r\n", emailfrom);
which is small enough it won't cause problems on any real destination
but large enough to be useful. If you know more about the destinations
you will be talking to, and need to, could increase accordingly.

Aside: for limiting sprintf in general in a C99 implementation (rare)
or as an extension to C89 (more common) you can use snprintf. However,
it truncates without regard to the data content, which in this case
gives you a malformed command.
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
You should always check the SMTP response before continuing. In theory
you should even have checked the banner.
strcpy(line,"RCPT TO:<");
strncat(line,emailto,strlen(emailto));
strncat(line,">\n",3);
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
Ditto and ditto, and more below.
strcpy(line,"DATA\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
sleep(waittime);
strcpy(line,"To:");
strcat(line,emailto);
strcat(line,"\n");
strcat(line,"From:");
strcat(line,emailfrom);
strcat(line,"\n");
strcat(line,"Subject:");
strcat(line,emailsubject);
strcat(line,"\n");
strcat(line,emailmessage);
strcat(line,"\r\n.\r\n");
You finally got (part of) one right -- probably because without it
some servers weren't Postelian enough to recognize the (vital) EOM.
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
strcpy(line,"quit\n");
fputs(line,smtpfile);
bytes_sent=send(sockfd,line,strlen(line),0);
sleep(waittime);
err=recv(sockfd,Rec_Buf,bufsize,0);Rec_Buf[err] = '\0';
fputs(Rec_Buf,smtpfile);
fclose(smtpfile);
#ifdef WIN32
closesocket(sockfd);
WSACleanup();
#else
close(sockfd);
#endif
You don't free(Rec_Buf); this is a memory leak.
}

however, my mailserver(for which i pay for hosting) is tls only for
security, and requires authentication, so I am not sure how to modify
the code to authenticate over tls and send an email....

Almost certainly your best bet is to use openssl, an opensource
library, if BSD-style terms are acceptable. See www.openssl.org.

Even so, it's not trivial; SSL/TLS is a pretty big protocol,
especially with all the options. At the level of understanding this
code displays, if your systems allow it, which both Windows and (any)
Unix do, you might be better off using system() to invoke a separate
(prebuilt) mail-sending program.

- David.Thompson1 at worldnet.att.net
Mar 20 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.