Version 41 of smtp

Updated 2011-01-19 08:10:21 by pascal

Simple Mail Transfer Protocol

Documentation on the Tcl package in tcllib for SMTP [L1 ] can be found at http://tcllib.sourceforge.net/doc/smtp.html


NOTE SMTP (at least up to 1.4.5) will silently fail to authenticate if [package require SASL] fails. If you're using teacup, make sure SASL is available, as it wasn't listed as a dependency for SMTP as of 2011-01-19.


Here's a minimal useful example:

      proc send_simple_message {recipient email_server subject body} {
          package require smtp
          package require mime

          set token [mime::initialize -canonical text/plain -string $body]
          mime::setheader $token Subject $subject
          smtp::sendmessage $token \
                  -recipients $recipient -servers $email_server
          mime::finalize $token
      }

      send_simple_message [email protected] localhost \
                "This is the subject." "This is the message."

OK, this is more minimal:

         ...
      set token [mime::initialize -canonical text/plain -string $body]
      smtp::sendmessage $token \
              -header [list Subject $subject] \
              -header [list To $recipient]
      mime::finalize $token
         ...

This last one didn't work for me; I kept getting an error from sendmessage about { } not being a valid option. -- WHD.

WHD, CL will make a point of returning in July 2002 [giggle - doesn't look like he made it back...] to address this error. What's above certainly worked with ... well, *some* version.

See also http://www.magma.ca/~glennj/tcl/mutt_sendmail.tcl.txt


PT 8-July-2004: Here is a rather more complex example that can handle an authenticating SMTP server.

 set tok [mime::initialize -canonical text/plain -string $TEXT]
 smtp::sendmessage $tok \
        -servers [list $SERVER] -ports [list $PORT] \
        -usetls 1 \
        -username $USERNAME \
        -password $PASSWORD \
        -header [list From "$FROM"] \
        -header [list To "$TO"] \
        -header [list Subject "$SUBJECT"] \
        -header [list Date "[clock format [clock seconds]]"]    
 mime::finalize $tok

Note: if you have trouble with sending mail, adding -debug 1 as an option to the [sendmessage] command will log the SMTP conversation and may help diagnose problems.

MHo 2007-Sep-20:

  • Can't find -debug 1 on the man page.
  • Where does the output goes to? I see nothing.

PT Not being on the man page doesn't mean it's not there. Output is to stderr. MHo: Thanks. Just couldn't catch this. Now using console show and I see what I wanted.-


SV: See also SMTP with attachments


CMcC 2005-02-20: I have put together a first cut asynchronous SMTP client here [L2 ] ... I'd be interested to see if it works for people.

The design is moderately interesting. It's a snit object which is mostly composed of methods of the form X-Y where X is the protocol command last issued, and Y is a glob to match the server's response code. This is a finite state machine, and the fileevent bubbles through it driven by responses from the server.

Given this FSA design, it should be easy enough to use the tcllib finite state machine to drive it, too, if that were desired. I have reservations about too great a reliance on FSA as a programming technique, though.

escargo 20 Sep 2007 - Which finite state machine in tcllib do you mean? The mentions I saw all related to the grammar package.


JMN 2006-03-30 I think the strong Tie-in (as it currently stands) between the MIME package and client SMTP library here is a little unfortunate. This is not ideal for a whole class of applications where the message is already in mime format but needs to be submitted to an SMTP server - I'm putting this note here lest people try building mail components using this library - and in unnecessarily re-parsing mime messages find the performance (especially with large messages) woeful..

Even using the '-canonical text/plain' option during mime::initialize doesn't help much because a) If you already have a message that includes all the headers - this header information ends up in the *body* of the new message. - This means you need to separate out your headers from the body prior to calling sendmessage. Presumably this means for a multipart message you'd have to use the MIME package rather than simply splitting on the first blank line. i.e unnecessary re-parsing of the whole (potentially very large) message.

b) This smtp library forces you to load the entire message in memory - i.e it doesn't support streaming large messages from a Tcl channel to the SMTP socket. (not really a complaint about the mime/smtp tie-in - but something to take note of.)

It should be noted that Tcl can be used very effectively for SMTP & message handling applications. I've built an SMTP Message Submission Agent entirely in TCL that receives multiple multi-megabyte mime-formatted messages concurrently with no trouble on very modest hardware. The messages arrive already mime-encoded.. and after an intermediate stage on disk, are submitted to another SMTP server with a few additional header lines. The only use of the tcllib MIME package in this case was for the handy mime::parseaddress feature.


During May, 2008, Twylite wrote, on comp.lang.tcl [L3 ] a message showing an example of code in response to a question of why a user's smtp attempts were returning an error saying that the message-id header was missing:

We've seen that when using SMTP AUTH in conjunction with MS Exchange. 
The problem was related to the use of mime::setheader instead of 
including the headers as options to smtp::sendmessage.  Not sure _why_ 
this was a problem, it just was. 

This code works for us: 


package require mime 
package require smtp 


proc send_email {from to subject body} { 


  set opts {} 
  lappend opts -servers list 10.0.0.1 
  lappend opts -ports list 25 
  lappend opts -username user 
  lappend opts -password pass 
  lappend opts -header list "Subject" $subject 
  lappend opts -header list "From" $from 
  lappend opts -header list "To" $to 


  set mime_msg [mime::initialize -canonical "text/plain" -encoding 
"7bit" \ 
    -string $body] 


  smtp::sendmessage $mime_msg {*}$opts -queue false -atleastone false - 
usetls false 


  mime::finalize $mime_msg 



} 


send_email "Twylite <twylite@mydomain>" "Person <someone@somewhere>" 
"Test" { 
  This is my mail message. 


} 

See also: