Version 22 of pop3

Updated 2003-08-20 03:01:37

Documentation can be found at http://tcllib.sourceforge.net/doc/pop3.html .

 if 0 {
     package require pop3  ;# http://tcllib.sourceforge.net/

     set popsock             [pop3::open $_theHost $_theUser $_thePassword]
     foreach {msgcount size} [pop3::status   $popsock] {}
     set message             [pop3::retrieve $popsock $_index]
     set messages            [pop3::retrieve $popsock $_first $_last]
                              pop3::delete   $popsock $_index
                              pop3::delete   $popsock $_first $_last
                              pop3::close    $popsock
 }

[Add commentary to above. Explain foreach idiom. Mention exceptions.]

VL 21 may 2003: -ERR autorization first, if you recieve this error during pop3::open a likely explanation is that the email-server does not accept connections through telnet, only through SSH. VL 19 aug 2003: I think that there are instructions included with most SSH-clients about how to set up port forward/tunneling. At least there is in the Putty documentation [L1 ]

escargo 21 May 2003 - I put if 0 { around the code so that this page becomes reapable; the check mail code should then just work if collected by wish-reaper and friends.


[Explain performance considerations, version compatibility, head use, exception-handling, ... Warn about deletes. Point to pertinent RFC for index base and other definitions.]


A little pop3 client demo, using the tcllib: Steve Offutt, 5/25/01 mailto:[email protected] Thanks to Cameron for help getting started.


escargo 21 May 2003 - If you push the "Disconnect" button to disconnect, and then push it again, an error results. The close_it proc does not check to see if the popsock value is empty before trying to close it.


 # Check Mail - a lightweight pop3 client - Thursday May 31, 2001

 package require pop3

 #create a user interface
 proc make_gui { } {

        label .lhost -text "Hostname"
        label .luser -text "Username"
        label .lpass -text "Password"   

        entry .eh -textvariable "_theHost"
        entry .eu -textvariable "_theUser"
        entry .ep -textvariable "_thePassword"

        bind .ep <Return> {open_channel}

        button .b -text "Connect" -command {open_channel}
        button .b2 -text "Disconnect" -command {close_it}

        set popsock ""
        label .lsock -text "Socket:"
        label .lsock2 -relief groove -bd 2

        grid .lhost .eh -sticky ew
        grid .luser .eu -sticky ew
        grid .lpass .ep -sticky ew
        grid .lsock .lsock2 -row 3  -sticky ew
        grid .b -row 4 -columnspan 2 -sticky ew
        grid .b2 -row 5 -columnspan 2 -sticky ew

        .ep configure -show *
        }
 make_gui


 #globals
 global new_messages
 set new_messages 0

 global popsock
 set popsock ""

 #procedures follow
 proc open_channel { } {
        global _theHost _theUser _thePassword popsock
        set popsock [pop3::open $_theHost $_theUser $_thePassword]
        .lsock2 configure -text $popsock
        get_status
        return $popsock
        }

 proc close_it { } {
        global popsock
        close $popsock
        set popsock ""
        .lsock2 configure -text ""
        return $popsock
        }

 proc get_status { } {
        global popsock 
        set my_stat [pop3::status $popsock]
        set new_messages [lindex $my_stat 0]
        show_it $new_messages
        return $new_messages
        }

 proc show_it { var } {
        tk_messageBox -icon info -title "Messages" \
        -parent . -type ok -message "You have $var new messages."       

         #xception-handling, ...  Warn about deletes.  Point to pertinent RFC for index base and other definitions.]
        }

 proc tkerror { errmsg } {
        global errorCode
        set msg [format "Error: %s\nResult: %s." $errmsg $errorCode]
        tk_messageBox -parent . -title Error -type ok\
                -icon error -message $msg
        bell
        }

 wm protocol . WM_DELETE_WINDOW "clean_up"

 proc clean_up { } {
        global popsock
        if {$popsock != ""} {
                close_it
                }
        exit
        }

 wm title . "Check Mail"
 wm deiconify .
 focus .eh

NOTE: Most pop3 servers only allow one client to connect at a time. That's what RFC 1939 [L2 ] requires.

AK: Actually the note above is too restrictive. The RFC says that a server should allow only one client/connection per maildrop. In other words, a pop3 server managing N different maildrops can have N connections from N clients, if these connections all talk to a different maildrop.

NOTE: RFC 1939 [L3 ] (which is a standard) is updated by RFC 1957 [L4 ] (informational), and RFC 2449 [L5 ] (standards track). -EE

(My information comes from http://www.rfc-editor.org/ , which is pretty much the canonical source of RFC information.)

Only marginally on topic, we also have RFC 2384 [L6 ].


Remember, one doesn't do a package require of tcllib itself, but of the modules INSIDE tcllib...


If you had only an old, socket-less Tcl at hand, but also Expect, you could exploit the Unix telnet binary, as Glenn Jackman's checkpopmail [L7 ] exemplifies.

Or maybe, you just copy Glenn Jackman's script once you realize that you want to check your IMAP mail account -- see Checking your IMAP Mail with Expect.


A small mail check utility. Checks a mailbox every 10 minutes. Displays number of messages in the mailbox and time of the last check. Number of messages is also displayed on title.

 package require pop3

 label .l -text "connecting...                          "
 button .chnow -text {Check now} -command checkMailBox
 pack .l .chnow
 update


 proc checkMailBox {} {
         wm title . "checking..."
         update
         if {[catch {set mch [::pop3::open -retr-mode list your-pop-server your-user-name your-password]} loginErr]} {
                 tk_messageBox -message $loginErr
                 .l configure -text "[clock format [clock seconds] -format %H:%M:%S]: - ERROR                "
                 wm title . "m - ERROR"
         } else {
                 set mBoxStat [::pop3::status $mch]
                 set systemTime [clock seconds]

                 .l configure -text "[clock format $systemTime -format %H:%M:%S]: [lindex $mBoxStat 0] messages on the server..."
                 ::pop3::close $mch 
                 wm title . "m - [lindex $mBoxStat 0]"
                 after [expr 1000 * 60 * 10] checkMailBox
         }
 }

 checkMailBox

Luciano ES Also check out similar mail box polling code at procmail sux


escargo 19 Aug 2003 - Has anyone build any anti-spam tools using pop3 as a base? The spam filters provided by my ISP are not ones I can control, so I can't tune them myself. Also, their pattern matching leaves a lot to be desired (things that are obvious to the human eye are defeating the scanners). Unlike SpamMap, I would like a program I could run from my client machine that would postprocess e-mail from my ISP, and have it ask me about killing things that it sees. This would save me a lot of manual clicking and so forth to create filters on my existing mail client.

LES - I started something just like that, but haven't found the time to finish it. Basically, it's what I suggest in procmail sux. Look for that line that says "filtering code here" and off you go.


Category Package, subset tcllib