Updated 2016-08-09 02:45:58 by ray2501

Simple Mail Transfer Protocol

Documentation on the Tcl package in tcllib for SMTP [1] can be found at http://core.tcl.tk/tcllib/doc/trunk/embedded/www/tcllib/files/modules/mime/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 [2] ... 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 [3] 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] 
  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 <[email protected]>" "Person <[email protected]>" 
"Test" { 
  This is my mail message. 

See also:

[PatJansen] - 2012-09-13 11:26:53

I spent several days trying to send email through both smtp.gmail.com and my local MS Exchange using authentication but without success. I finally managed to get it working using the code below. This procedure was run from withn PostgreSQL using pltclu.

I hope it helps at least one person.
create or replace function pgmail(text, text, text, text,text,text,text,text) returns int4 AS $$
package require smtp
package require mime
set mailfrom $1
set mailto $2
set mailsubject $3
set body $4
set myHost $5
set myPort $6
set myUname $7
set myUpassword $8

set token [mime::initialize -canonical "text/plain" -encoding "7bit" -string $body]
          mime::setheader $token Subject $mailsubject
          smtp::sendmessage $token \
                        -servers [list $myHost] -ports [list $myPort]\
                        -usetls true\
                        -debug true\
                        -username $myUname \
                        -password $myUpassword\
                        -queue false\
                        -atleastone true\
                        -header [list From "$mailfrom"] \
                        -header [list To "$mailto"] \
                        -header [list Subject "$mailsubject"]\
                        -header [list Date "[clock format [clock seconds]]"]
          mime::finalize $token
return 1
$$ LANGUAGE pltclu;>

[Gmailuser] - 2016-08-08


This does not work for online email providers like Yahoo or Gmail. In fact, none of the other smtp related code on this wiki works.

Gmail and Yahoo use port 587 and require TLS. Even when these are enabled in the code above, one can't send email messages due to various errors such as socket and channel errors, unexpected end of file, etc.

I would like to use Tcl to send messages to myself at my gmail account and using gmail as the smtp provider. Is this possible at all or does Tcl only work with basic SMTP at port 25?

TLS support please check smtp package document: http://core.tcl.tk/tcllib/doc/trunk/embedded/www/tcllib/files/modules/mime/smtp.html#section4

And check stackoverflow answer: (Tcl) Sending e-mails via gmail and yahoo mail servers

See also SMTP Mail with Jim