Simple Mail Transfer Protocol

From Scriptwiki
Revision as of 14:29, 9 July 2007 by Aca20031 (talk | contribs) (Fixed link)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Simple Mail Transfer Protocol (Commonly called SMTP for short) is the most used method of sending email across the internet. SMTP is an indirect method of sending email, which means you will need a mail server instead of directly connecting to one. Most ISPs (Internet Service Providers, such as MSN or Earthlink) have their own mail server for SMTP that you must use, for example mail.comcast.net, mail.earthlink.net. If you use POP3 mail through a reader such as Outlook or Outlook Express, you should check your account settings in them to find out which SMTP mail server you use, and use the same one.

Note, you will need to have good knowledge of sockets in MSL before attempting this.

The Connection

Before we can do anything we have to establish a connection with the mail server and tell it our intentions. Let's set up a configuration alias for this shall we?

alias -l smtp {
 if ($prop == server) return mail.earthlink.net
 if ($prop == from) return tutorial_test@script.quakenet.org
}

Now we will be able to reference static data with $smtp() for connection and configuration purposes. You could easily have this return a variable if you were to put this into a public and customizable script. Even now, however, if you do not use Earthlink as an ISP, you will need to change the mail server to an SMTP server you have access to. Try mail.myisp.xxx

Now, our alias to connect with this data:

alias -l smtp.connect {
 set %smtp.authd $false
  if ($sock(smtp)) sockclose smtp
 sockopen smtp $smtp().server 25
}


Notice we are using the -l (local) switch, this is because we only intend to use this aliases internally. The %smtp.authd alias will be used later, and simply needed to be reset when a new email was sent.

Reading from the Connection

Now we'll need a simple sockread event to receive the data.

on *:SOCKREAD:smtp: {
 var %data
 sockread -n %data
 echo -atg Unhandled: %data
}

Setting up our Public Alias

Now we will want the alias for outside scripts, or users, to call. Let's have it take the to address and message as parameters

alias send_mail {
 if (!$2) return
 set %smtp.to $1
 set %smtp.msg $2-
 smtp.connect
}

For now, all we need to do is connect, we do not yet know what the server wants us to send it.

Responding to the Server

We now take a look at what was sent to us and construct our sockread event to respond accordingly.

Welcome Messages

The server starts off by sending a series of welcome messages, denoted by "220", so we start here. We need to reply to these welcome messages by replying with our domain.

on *:SOCKREAD:smtp: {
 var %data
 sockread -n %data
 var %reply = sockwrite -n smtp
 if (220* iswm %data && %smtp.authd == $false) {
   %reply HELO $host
   set %smtp.authd $true
 }
 else { echo -atg Unhandled: %data }
}

Here, when we see 220 at the start of a message, we will send HELO ourDomain. Note we only want to send this once or the server will act strange to a consecutive identification, so re set %smtp.authd to remind us we have already authenticated in case it sends more than one welcome message.

Now let's try to send again.

/send_mail myemail@mydomain Test Message

Now we see a new message, 250, that acknowledges our domain and says hello, as an added friendly method. Once we see this, we will want to tell it where to send our mail, and who it is from..

To and From

The 250 raw is a generic "OK" so we will have to be smart in figuring out just what it's saying OK too. Lets create a variable, %smtp.step, that will remember what step we are on and therefore just what went "OK". Let's also start step at 0 when we see the HELLO from the server. We also want to send it the next bit of information in the protocol, who the mail is from, at this point.

on *:SOCKREAD:smtp: {
 var %data
 sockread -n %data
 var %reply = sockwrite -n smtp
 if (220* iswm %data && %smtp.authd == $false) {
   %reply HELO $host
   set %smtp.authd $true
 }
 elseif (250*Hello* iswm %data) {
   set %smtp.step 0
   %reply MAIL FROM:< $+ $smtp().from $+ >
 }
 else { echo -atg Unhandled: %data }
}

After this you will received another 250 message saying you did fine, now it's time to move on to who the mail is intended for, which we stored in %smtp.to - we will know it is time for this if %smtp.step is 0 and we receive a 250.

elseif (250 * iswm %data && %smtp.step == 0) {
  inc %smtp.step
  %reply RCPT TO:< $+ %smtp.to $+ >
}

And again, a 250 message will confirm we did this right.

Sending Data

Now it is time to tell it what to send. We tell the server we are ready by sending "DATA"

elseif (250 * iswm %data && %smtp.step == 1) {
  inc %smtp.step
  %reply DATA
}

The server replies with 354 saying it is ready to get our data, and that we should end it with <line>.<line> when we have finished, so that it knows we are indeed done. Let's give it our data then.

 elseif (354 * iswm %data && %smtp.step > 1) {
   %reply Subject: Test Tutorial Message
   %reply From: My Bot < $+ $smtp().from $+ >
   %reply To: Esteemed Tester < $+ %smtp.to $+ >
   %reply
   %reply %smtp.msg
   %reply ====
   %reply This has been a message from $me on IRC server $server
   %reply
   %reply .
 }

And the server gives us its last OK, and gives us the ID of the message we just sent. After this, we can tell it we are done by sending QUIT.

  elseif (250 * iswm %data && %smtp.step == 2) {
   %reply QUIT
   inc %smtp.step
 }

The server sends 221 which is a "goodbye" message, and closes the connection. Now you that we are done, we can remove the "unhandled" line printing, because we are no longer interested in what the server says, we know our script will take care of it!

Finished Script

Now at we are done we can send mail to anyone by typing /send_mail target message

//send_mail myself@yahoo.com Hello $+ $crlf $+ This is a message on more than one line.

Here is what I have, you may use this and modify it however you would like:

alias -l smtp {
 if ($prop == server) return mail.earthlink.net
 if ($prop == from) return tutorial_test@script.quakenet.org
}
alias -l smtp.connect {
 set %smtp.authd $false
 if ($sock(smtp)) sockclose smtp
 sockopen smtp $smtp().server 25
}
on *:SOCKREAD:smtp: {
 var %data
 sockread -n %data
 var %reply = sockwrite -n smtp
 if (220* iswm %data && %smtp.authd == $false) {
   %reply HELO $host
   set %smtp.authd $true
 }
 elseif (250*Hello* iswm %data) {
   set %smtp.step 0
   %reply MAIL FROM:< $+ $smtp().from $+ >
 }
 elseif (250 * iswm %data && %smtp.step == 0) {
   inc %smtp.step
   %reply RCPT TO:< $+ %smtp.to $+ >
 }
 elseif (250 * iswm %data && %smtp.step == 1) {
   inc %smtp.step
   %reply DATA
 }
 elseif (354 * iswm %data && %smtp.step > 1) {
   %reply Subject: Test Tutorial Message
   %reply From: My Bot < $+ $smtp().from $+ >
   %reply To: Esteemed Tester < $+ %smtp.to $+ >
   %reply
   %reply %smtp.msg
   %reply ====
   %reply This has been a message from $me on IRC server $server
   %reply
   %reply .
 }
 elseif (250 * iswm %data && %smtp.step == 2) {
   %reply QUIT
   inc %smtp.step
 }
}
alias send_mail {
 if (!$2) return
 set %smtp.to $1
 set %smtp.msg $2-
 smtp.connect
}