Welcome to Linux Forums! With a comprehensive Linux Forum, information on various types of Linux software and many Linux Reviews articles, we have all the knowledge you need a click away, or accessible via our knowledgeable members.
Find the answer to your Linux question:
Site Navigation
Linux Forums
Linux Articles
Product Showcase
Linux Downloads
Linux Hosting
Free Magazines
Job Board
IRC Chat
RSS Feeds
Free Publications


Sending e-mail from the command line is something very easy to do with the plethora of tools available under linux for this. mail,mutt, nail, nmh etc. come to mind.

However to directly talk SMTP commands to the target host and deliverthe mail is something that needs some more work.

Not that it cannot be done. netcat can be used along with HEREDOC forthis. But I am going to present a C program I wrote a little while ago.Let us take a look at it.
/* Copyright (c) 2007 Girish Venkatachalam
*
* Permission to use, copy, modify, and distribute
* this software for any
* purpose with or without fee is hereby granted,
* provided that the above copyright notice
* and this permission notice appear
* in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netdb.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#include <string.h>
#include <getopt.h>

#define TRUE 1

struct mx
{
int prio;
char host[1024];
};

#ifndef HFIXEDSZ
# define HFIXEDSZ 12
#endif
#ifndef INT16SZ
# define INT16SZ sizeof(cit_int16_t)
#endif
#ifndef INT32SZ
# define INT32SZ sizeof(cit_int32_t)
#endif

int mxcomp(int p[],int n)
{
if (p[1] > p[2]) return(1);
else if (p[1] < p[2]) return(0);
else return(random() % n);
}



void sort_mxrecs (struct mx *mxrecs, int nmx)
{
int a, b;
struct mx t1, t2;

if (nmx < 2) return;

/*
for (a = nmx - 2; a >= 0; --a)
{
for (b = 0; b <= a; ++b)
{
if (mxcomp(mxrecs[b].prio,mxrecs[b+1].prio))
{
memcpy(&t1, &mxrecs[b], sizeof(struct mx));
memcpy(&t2, &mxrecs[b+1], sizeof(struct mx));
memcpy(&mxrecs[b], &t2, sizeof(struct mx));
memcpy(&mxrecs[b+1], &t1, sizeof(struct mx));
}
}
}
*/
}



int getmxip(char *domain,struct in_addr *ip)
{
union
{
u_char bytes[1024];
HEADER header;
} ans;

int ret;
unsigned char *startptr, *endptr, *ptr;
char expanded_buf[1024];
unsigned short prio, type;
int n = 0;
int qdcount;

struct mx *mxrecs = NULL;
struct hostent *h;
int nmx = 0;

h = (struct hostent *)malloc(sizeof(struct hostent));
ret = res_query (domain, C_IN, T_MX, (unsigned char *)ans.bytes,
sizeof(ans));
if (ret < 0)
{
mxrecs = (struct mx *)malloc(sizeof(struct mx));
mxrecs[0].prio = 0;
strcpy(mxrecs[0].host, domain);
h = gethostbyname(domain);
memcpy(ip,h->h_addr,h->h_length);
nmx = 0;
}
else
{
if (ret > sizeof(ans)) ret = sizeof(ans);

startptr = &ans.bytes[0];
endptr = &ans.bytes[ret];
ptr = startptr + HFIXEDSZ; /* skip header */

for (qdcount = ntohs(ans.header.qdcount); qdcount--;
ptr += ret + QFIXEDSZ)
{
if ((ret = dn_skipname(ptr, endptr)) < 0) return(0);
}

while(TRUE)
{
memset (expanded_buf, 0, sizeof(expanded_buf));
ret = dn_expand (startptr, endptr, ptr, expanded_buf,
sizeof(expanded_buf));
if (ret < 0) break;
ptr += ret;

GETSHORT (type, ptr);
ptr += INT16SZ + INT32SZ;
GETSHORT (n, ptr);

if (type != T_MX) ptr += n;
else
{
GETSHORT(prio, ptr);
ret = dn_expand(startptr, endptr, ptr, expanded_buf,
sizeof(expanded_buf));
ptr += ret;

++nmx;
if (mxrecs == NULL)
mxrecs = (struct mx *)malloc(sizeof(struct mx));
else
mxrecs = (struct mx *)realloc (mxrecs, (sizeof(struct mx) * nmx));

mxrecs[nmx - 1].prio = prio;
strcpy(mxrecs[nmx - 1].host, expanded_buf);
}
}
}
sort_mxrecs(mxrecs, nmx);

h = gethostbyname(mxrecs[0].host);

memcpy(ip,h->h_addr,h->h_length);

{char *ipadd;

ipadd = inet_ntoa(*ip);
}

free(mxrecs);
return(nmx);
}

int pipe_file_to_server(int s,char *filename,char *sender,
char *sname,char *recipient,char *subject) {
int fd,b,bs;

char buf[8192],envelope[8192];

#define MSG "Please terminate mail with "

/*
* SMTP envelope format from rfc 2821
* : Received: from bar.com by foo.com ; Thu, 21 May 1998
* : 05:33:29 -0700
* : Date: Thu, 21 May 1998 05:33:22 -0700
* : From: John Q. Public

* : Subject: The Next Meeting of the
* board
* : To: Jones@xyz.com
* :
* : Bill:
*
*/
envelope[0] = 0; /* Initialize the buffer */
snprintf(buf,sizeof(buf),"From: %s <%s>rn",sname,sender);
strncat(envelope,buf,strlen(buf));
snprintf(buf,sizeof(buf),"To: <%s>rn",recipient);
strncat(envelope,buf,strlen(buf));
snprintf(buf,sizeof(buf),"Subject: %srn",subject);
strncat(envelope,buf,strlen(buf));
bs = send(s,envelope,strlen(envelope),0);

if( bs <= 0) {
perror("send()");
}

/* Blank line between envelope & body */
snprintf(buf,sizeof(buf),"rn");
bs = send(s,buf,strlen(buf),0);

if( bs <= 0) {
perror("send()");
}

if(NULL == filename) {
write(1,MSG,strlen(MSG));
fd = 0;
}
else {
fd = open(filename,O_RDONLY);
if (-1 == fd ) {
errx(1,"Couldn't open mail text file [%s]",filename);
}
}

while((b = read(fd,buf,sizeof(buf))) > 0) {

bs = send(s,buf,b,0);
if( bs < 0) {
perror("send()");
}
}

if(fd != 0)
close(fd);

}

int send_line(int s, char *buf,int n) {

int bs,r;
char rbuf[512];
int status;

bs = send(s,buf,n,0);

if (-1 == bs) {
perror("send()");

}

r = recv(s,rbuf,sizeof(rbuf),0);

if(-1 == r) {
perror("recv()");
}
rbuf[r] = 0;


status = strtoll(rbuf,NULL,10);

if(421 == status) {
printf("We are being greylisted");
}

if(status > 400) {
errx(1,"Trouble for us, let us get out of the
game..Exiting");
}
return 0;


}

int smtp_auth(int s,struct in_addr *ip, char *userid, char *password) {


/* Fill in later*/
return 0;
}
int send_mail(struct in_addr *ip,char *sender, char *sname,
char *recipient,char
*subject, char *userid,char *password,char *file) {

char sbuf[512],rcvbuf[512];
int s,rl,ret;
struct sockaddr_in mailhost;
char *localdomain = "susmita.org";
socklen_t l;
int status;

mailhost.sin_addr = *ip;
/* This could be 587 also... */
mailhost.sin_port = htons(25);
mailhost.sin_family = AF_INET;

l = sizeof(struct sockaddr_in);

s = socket(PF_INET,SOCK_STREAM,0);

if( s < 0) {
perror("socket");
}

ret = connect(s, (struct sockaddr *)&mailhost,l);

if(-1 == ret) {
perror("connect");
}


rl = recv(s,rcvbuf,sizeof(rcvbuf),0);

if(-1 == rl) {
perror("recv()");
}
puts(rcvbuf);
status = strtoll(rcvbuf,NULL,10);

if(421 == status) {
errx(1,"We are being greylisted");
}

if(status > 400) {
errx(1,"Trouble for us, let us get out of the
game..Exiting");
}

smtp_auth(s,ip,userid,password);

snprintf(sbuf,sizeof(sbuf),"HELO %srn",localdomain);
send_line(s,sbuf,strlen(sbuf));
snprintf(sbuf,sizeof(sbuf),"MAIL FROM:<%s>rn",sender);
send_line(s,sbuf,strlen(sbuf));
snprintf(sbuf,sizeof(sbuf),"RCPT TO:<%s>rn",recipient);
send_line(s,sbuf,strlen(sbuf));
snprintf(sbuf,sizeof(sbuf),"DATArn",recipient);
send_line(s,sbuf,strlen(sbuf));

pipe_file_to_server(s,file,sender,sname,recipient,subject);
snprintf(sbuf,sizeof(sbuf),"rn.rn",subject);
send_line(s,sbuf,strlen(sbuf));

return 0;


}

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

char buf[1024],prompt[512];
char *userid,*sender,*recipient,*domainname,*subject;
char *password,*sname,*mailtxtfile=NULL;
int op,status;
struct in_addr ip;

if(argc < 2) {

errx(-1,"Usage: n%s -u n
-s n
-n n
-r n
-S n
[-f ]n ",argv[0]);
}


while((op = getopt(argc,argv,"u:s:n:r:S:f:")) != EOF) {

switch (op) {
case 'u':
userid = optarg;
break;
case 's':
sender = optarg;
break;
case 'n':
sname = optarg;
break;
case 'r':
recipient = optarg;
break;
case 'S':
subject = optarg;
break;
case 'f':
mailtxtfile = optarg;
break;
default:
errx(1,"Unknown option");

}

}

domainname = strchr(recipient,'@')+1;

snprintf(prompt,sizeof(prompt),"Password for [%s]:",userid);
password = getpass(prompt);
getmxip(domainname, &ip);
status = send_mail(&ip,sender,sname,recipient,subject,userid,password,
mailtxtfile);

if(0 != status) {

errx(1,"Sending mail failed");
perror("SMTP");
}


}


As you can see, it is a simple program that uses plain text commands for sending an e-mail with the right headers. You are free to tweak it to suit your taste.

Remember that sending e-mail has nothing to do with receiving mail. It uses a completely different wire protocol. POP3 is popular but IMAP is a much more powerful alternative. IMAP saves precious bandwidth as it has support for a powerful query language for scanning the headers.

E-mail headers are a topic in itself and it has attained even more significance with the growing spam and the various alternatives to control it. You can add custom headers with the prefix "X-" and a good look at the headers of your mail message can be quite educational.

Spam control is a topic of intense research activity and I cannot do justice to it in this article. However no mention of e-mail will be complete without a mention of spam as well.

Basically spam is unsolicited bulk mail. And the defintion of spam varies from individuals to individuals. I may love ice creams but you might not like it. Especially when you did not order for it. This makes spam control slightly more complicated. Due to this and various other reasons user feedback has become critical for spam control and it is not unusual to refer to a common database or "spam corpus" which is populated by humans. If you think a particular mail is spam and several others share this view, it is very likely another person will view it as spam as well.

There are several approaches to control/mitigate spam at the SMTP relay level itself using SMTP 4xx reply messages. This is called teergrubing, greytrapping,greylisting,whitelisting, blacklisting, greenlisting and so on.

Bayesian probability theory comes in handy and so does Markovian chains for identifying patterns in text and html tags.

Spam or no spam, e-mails have become an unalienable part of our modern communications infrastructure. I hope this article serves as a good introduction to the innards of this marvellous tool.

Rate This Article: poorexcellent
 
Comments about this article
code
writen by: Predatorian on 2007-09-11 11:47:46
the code you listed here is only for *nix systems right? this may seem dumb, but is there a windows version to it also? im very new to programming, did a little research but the answers i found said i had to change something but it seems they left something out.
RE: code written by Predatorian:
Mr
writen by: Hrudayanath Kommareddy on 2007-11-13 01:55:20
This code sample seems to be nice..But I am more of AI guy who would like to learn more about Statistical techniques used to control email spam. So,Please elaborate more on above thanks hruday
RE: Mr written by Hrudayanath Kommareddy:

Comment title: * please do not put your response text here