Cisco Support Community
cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Announcements

Webcast- Automate Nexus9k

Cisco Employee

Re: Send MAIL TCL not working

You haven't renamed any of the functions.  Technically, you can remove everything from the library except the namespace definition and the smtp_send_email and smtp_connect functions.  Change the name of these functions to ::cisco::lib::my_smtp_send_email and ::cisco::lib::my_smtp_connect respectively.  In the new my_smtp_send_email function, change the call to smtp_connect to my_smtp_connect.

Then load your new library into your user library directory.  While flash: is fine, you should create a subdirectory to hold library files (e.g., flash:/eem_lib).  Then reconfigure your user library directory.  Then change your EEM policy to call my_smtp_send_email, and everything should work.

Community Member

Hi Joseph. I was wondering if

Hi Joseph. I was wondering if there is anyway I can edit the file tmpsys:/lib/tcl/smtp_lib.tcl

What would really solve my problem is to make this smtp_lib connect to port 587 instead of port 25. 

When I try to do it I get a permission denied:

R-2801#copy tftp://10.0.0.10/smtp_lib.tcl tmpsys:/lib/tcl/
Destination filename [/lib/tcl/smtp_lib.tcl]?
Accessing tftp://10.0.0.10/smtp_lib.tcl...
Loading smtp_lib.tcl from 10.0.0.10 (via FastEthernet0/1): !
%Error opening tmpsys:/lib/tcl/smtp_lib.tcl (Permission denied)

 

Can I make this copy somehow?

 

Cisco Employee

No, you'll have to modify the

No, you'll have to modify the file and create a new module.  The tmpsys location cannot be touched directly.

Community Member

Re: Send MAIL TCL not working

In my head, to solve this I should have nameespace like this, but I don´t know how to write this:

::cisco::eem::event_register_syslog occurs 1 pattern ".*1 list boolean or.*"

namespace import ::cisco::eem::*

namespace import ::flash::custom_smtp_lib.tcl

Community Member

Re: Send MAIL TCL not working

Also, somehow I could temporarelly change the tmpsys:/lib to rw and update the smtp_lib.tcl but there is no such chmod command.

Community Member

Re: Send MAIL TCL not working

Hi Joseph,

This is what I did:

FILE mail2.tcl:

::cisco::eem::event_register_syslog occurs 1 pattern ".*1 list boolean or.*"

namespace import ::cisco::lib::my_smtp_send_email

namespace import ::cisco::lib::my_smtp_connect

set mail_pre "Mailservername: marcelo@xxx.com.br:xxx@177.73.xxx.xxx\n"

append mail_pre "From: marcelo@xxx.com.br\n"

append mail_pre "To: xxx@gmail.com\n"

append mail_pre "Cc: \n"

append mail_pre "Subject: Link Virtua DOWN\n"

append mail_pre "Teste\n\n"

set mail_msg [uplevel #0 [list subst -nobackslashes -nocommands $mail_pre]]

if [catch {my_smtp_send_email $mail_msg} result] {

    error $result $errorInfo

}

/*****************************************************/

FILE custom_smtp_lib.tcl:

#------------------------------------------------------------------

# SMTP client Tcl Library.

#

# Dec. 1999, Yu Zhang

#

# Copyright (c) 1999-2003, 2005-2008 by cisco Systems, Inc.

# All rights reserved.

#------------------------------------------------------------------

namespace eval ::cisco::lib {

  namespace export smtp_subst my_smtp_send_email

  # messages corresponding to SMTP reply codes

  variable reply_code_str

  set reply_code_str(211) "System status, or system help reply"

  set reply_code_str(214) "Help message"

  set reply_code_str(220) "Service ready"

  set reply_code_str(221) "Service closing transmission channel"

  set reply_code_str(235) "Authentication successful"

  set reply_code_str(250) "Requested mail action okay, completed"

  set reply_code_str(251) "User not local; will forward to some forward-path"

  set reply_code_str(334) "Password"

  set reply_code_str(354) "Start mail input; end with ."

  set reply_code_str(421) "Service not available, closing transmission channel"

  set reply_code_str(450) "Requested mail action not taken: mailbox unavailable"

  set reply_code_str(451) "Requested action aborted: local error in processing"

  set reply_code_str(452) "Requested action not taken: insufficient system storage"

  set reply_code_str(500) "Syntax error, command unrecognized"

  set reply_code_str(501) "Syntax error in parameters or arguments"

  set reply_code_str(502) "Command not implemented"

  set reply_code_str(503) "Bad sequence of commands"

  set reply_code_str(504) "Command parameter not implemented"

  set reply_code_str(550) "Requested action not taken: mailbox unavailable"

  set reply_code_str(551) "User not local; please try forward-path"

  set reply_code_str(552) "Requested mail action aborted: exceeded storage allocation"

  set reply_code_str(553) "Requested action not taken: mailbox name not allowed"

  set reply_code_str(554) "Transaction failed"

}

# Write a message 'msg' to the given smtp socket 'sock'.

# Possible error raised:

#           None.

proc ::cisco::lib::smtp_write { sock msg } {

  ::cisco::eem::smtp_debug "smtp_write" "$msg"

  puts $sock "$msg"

  flush $sock

  return

}

proc ::cisco::lib::smtp_write_nodebug { sock msg } {

  puts $sock "$msg"

  flush $sock

  return

}

# Synchronously read one line from the  given smtp socket 'sock'.

# Possible error raised:

#           None.

proc ::cisco::lib::smtp_read { sock } {

  set t [gets $sock k]

  if { $k == "" && $t == -1} {

      return -1

      ::cisco::eem::smtp_debug "smtp_read " "-1"

  }

  ::cisco::eem::smtp_debug "smtp_read " "$k"

  return $k

}

# Check the reply code of the given connection. If it is not successful,

# raise an error with the corresponding error message. Also used to

# synchronize the request and reply.

proc ::cisco::lib::smtp_chk_reply { sock succ_code } {

  variable reply_code_str

  set r [ smtp_read $sock ]

  if {$r == -1} {

      return -code error "Socket closed by remote server"

  }

  set k [lindex $r 0]

  if {$k != $succ_code} {

      return -code error [concat From SMTP server: $r\n$reply_code_str($k)]

  }

  return

}

# Given the text of an email template file with all global variables

# Try to open a socket to any of the candidate mail servers.

# Return the first socket successfully opened.

# Possible error raised:

# 1. $sock closed by remote server

# 2. $sock reply code is $k instead of the service ready greeting

# 3. cannot connect to all the candidate mail servers

proc ::cisco::lib::my_smtp_connect { svrlist srcipaddr srcintname} {

  global _username _userpass

  set num_retries 4

  set retry_delay 3000

  set l [llength $svrlist]

  for {set attempt 1} {$attempt <= [ expr $num_retries + 1 ]} {incr attempt} {

      ::cisco::eem::smtp_debug "my_smtp_connect" "attempt $attempt"

      for {set i 0} {$i < [ expr $l ]} {incr i} { 

          set svr [lindex $svrlist $i]

  # parse svr field which can be

  # username:password@host

  # username@host

  # host

          regexp {(.+@)?(.*)$} $svr match uidpwd svrhost

          regexp {(.+\:)?(.*)$} $uidpwd match a1 a2

          #  $a2 will be the uid if no password specified

          if { $a1 != "" } {

              set uid $a1

              set pwd $a2

          } else {

              set uid [string trimright $a2 @]

              set pwd ""

          }

  set _username [::base64::encode [string trimright $uid :] ]

  set _userpass [::base64::encode [string trimright $pwd @] ]

          if {[info exists sock]} {

              unset sock

          }

          if { $srcipaddr != "" } {

              catch [set sock [ socket -myaddr $srcipaddr $svrhost 587 ]]

          } else {

              if { $srcintname != "" } {

                  set srcipaddr [ intf_get_ip $srcintname $svrhost ]

                  catch [set sock [ socket -myaddr $srcipaddr $svrhost 587 ]]

              } else {

                  catch [set sock [ socket $svrhost 587 ]]

              }

  }

          if {![info exists sock]} {

              continue

          }

          if [catch {smtp_chk_reply $sock 220} result] {

              return -code error $result

          }

          return $sock

      }

      if {$attempt < [ expr $num_retries + 1 ]} {

          after $retry_delay

      }

  }

  return -code error "cannot connect to all the candidate mail servers"

}

# Disconnect the given socket.

# Possible error raised:

# 1. $sock closed by remote server

proc ::cisco::lib::smtp_disconnect { sock } {

  smtp_write $sock "QUIT"

  if [catch {smtp_chk_reply $sock 221} result] {

        return -code error $result

  }

  return

}

# Given an email template file 'email_template' , substitute each global

# variables in the file by its user-defined value. Return the text of the

# file after substitution.

# Possible error raised:

# 1. cannot open email template file

# 2. cannot close email template file

proc ::cisco::lib::smtp_subst { f } {

  if [catch {open $f r} result] {

      return -code error "cannot open email template file: $result"

  } else {

      set fid $result

  }

  set stxt [read $fid]

  if [catch {close $fid} result] {

      return -code error "cannot close email template file: $result"

  }

  # using subst to replace optional args

  # need to eval on top level to get the values of user defined args

  set dtxt [uplevel #0 [list subst -nobackslashes -nocommands  $stxt]]

  return $dtxt

}

# already substituted, send the email out using SMTP protocol. The

# email template specifies the candidate mail server addresses, To

# addresses, Cc addresses, From address, subject line and email body.

# Possible error raised:

# 1. wrong 1st line format

#    usage: Mailservername:

# 2. wrong 2nd line format

#    usage: From:

# 3. wrong 3rd line format

#    usage: To:

# 4. wrong 4th line format

#    usage: Cc:

# 5. error connecting to mail server:

#    $sock closed by remote server

#    (where $sock is name of the socket opened to the mail server)

# 6. error connecting to mail server:

#    $sock status code is $k instead of 220

#    (where $sock is name of the socket opened to the mail server,

#          $k is the reply code of $sock)

# 7. error connecting to mail server:

#    cannot connect to all the candidate mail servers

# 8. Host name is not configured

# 9. Domain name is not configured

#10. Any of the error message for non-OK SMTP reply code.

#11. error disconnecting from mail server:

#    $sock closed by remote server

#    (where $sock is name of the socket opened to the mail server)

proc ::cisco::lib::my_smtp_send_email { etxt } {

  global _domainname _username _userpass

  regsub -all "\r\n" $etxt "\n" etxt

  set linelist [split $etxt \n]

  # Below, be sure that mailsvrline, fromline, toline and

  # ccline can't have leading or trailing spaces

  # 1st line must be "Mailservername: ..."

  set svrline [string trim [lindex $linelist 0]]

  set svrlist [split $svrline { }]

  set len [llength $svrlist]

  if { [lindex $svrlist 0] != "Mailservername:" } {

        return -code error "wrong 1st line format. \nusage: Mailservername: "

  }

  #delete the first item

  set svrlist [lreplace $svrlist 0 0]

  # 2nd line must be "From: ..."

  set fromline [string trim [lindex $linelist 1]]

  set fromlist [split $fromline { }]

  set len [llength $fromlist]

  if { [lindex $fromlist 0] != "From:" || $len != 2} {

        return -code error "wrong 2nd line format. \nusage: From: "

  }

  set smtpsender [lindex $fromlist 1]

  # 3th line must be "To:" list

  set toline [string trim [lindex $linelist 2]]

  set tolist [split $toline \ ,\t]

  if { [lindex $tolist 0] != "To:" } {

        return -code error "wrong 3rd line format. \nusage: To: "

  }

  # delete the first item

  set tolist [lreplace $tolist 0 0] 

  # 4th line must be "Cc:" list

  set ccline [string trim [lindex $linelist 3]]

  set cclist [split $ccline \ ,\t]

  if { [lindex $cclist 0] != "Cc:" } {

        return -code error "wrong 4th line format. \nusage: Cc: "

  }

  #delete the first item

  set cclist [lreplace $cclist 0 0] 

  # 5th line optional. Can be "Sourceaddr:" or "Sourceintf:"

  set srcline [string trim [lindex $linelist 4]]

  set srclist [split $srcline { }]

  set srcaddr ""

  set srcintf ""

  if { [lindex $srclist 0] == "Sourceaddr:" } {

      set srcaddr [lindex $srclist 1]

      set linelist [lreplace $linelist 4 4]

  } else {

      if { [lindex $srclist 0] == "Sourceintf:" } {

          set srcintf [lindex $srclist 1]

          set linelist [lreplace $linelist 4 4]

      }

  }

  # compute receiver list

  set dest_list [concat $tolist $cclist]

  # connect to the mail servers and get a useful socket

  if [catch {my_smtp_connect $svrlist $srcaddr $srcintf} result] {

                return -code error "error connecting to mail server:\n$result"

  } else {

            set ssock $result

  }

  # on this sock, send mail file to all the receivers

  set l [llength $dest_list]

  set k [llength $linelist]

  set hostname [info hostname]

  if {[string match "" $hostname]} {

    return -code error "Host name is not configured"

  }

  if {![info exists _domainname]} {

    return -code error "Domain name is not configured"

  }

  smtp_write $ssock "HELO $hostname.$_domainname"

  if [catch {smtp_chk_reply $ssock 250} result] {

return -code error $result

  }

  if {[string length $_username]} {

smtp_write $ssock "AUTH LOGIN $_username"

        if [catch {smtp_chk_reply $ssock 334} result] {

      return -code error $result

}

if {[string length $_userpass]} {

      smtp_write $ssock "$_userpass"

      if [catch {smtp_chk_reply $ssock 235} result] {

            return -code error $result

              }

}

  }

  smtp_write $ssock "MAIL FROM:<$smtpsender>"

  if [catch {smtp_chk_reply $ssock 250} result] {

        return -code error $result

  }

  for {set i 0} {$i < [ expr $l ]} {incr i} { 

    set smtprcver [lindex $dest_list $i]

    smtp_write $ssock "RCPT TO:<$smtprcver>"

    if [catch {smtp_chk_reply $ssock 250} result] {

        continue

    }

  }

  smtp_write $ssock "DATA"

  if [catch {smtp_chk_reply $ssock 354} result] {

        return -code error $result

  }

  # write the body

  # write the date line

  smtp_write $ssock "Date: [clock format [clock seconds] \

-format "%d %b %Y %H:%M:%S %Z"]"

  # construct message id and write the message id line

  # Even there are multiple smtp clients running, the possibility

  # of same message ids are rare because in message id, we get

  # the time since bootup precise to nsec.

  array set stamp_since_boot [::cisco::eem::fts_get_stamp]

  set time_str [clock format [clock seconds] -format "%Y%m%d%H%M%S"]

  append time_str "." $stamp_since_boot(nsec)

  smtp_write $ssock "Message-ID: <$time_str@$hostname.$_domainname>"

  set debugbuffer ""

  # write the subject, from, to, cc and message data

  for {set j 1} {$j < [ expr $k ]} {incr j} {

     smtp_write_nodebug $ssock [lindex $linelist $j]

     append debugbuffer [lindex $linelist $j]

     append debugbuffer "\n"

  }

  ::cisco::eem::smtp_debug "smtp_write" "$debugbuffer"

  smtp_write $ssock "."

  if [catch {smtp_chk_reply $ssock 250} result] {

        return -code error $result

  }

  if [catch {smtp_disconnect $ssock} result] {

return -code error "error disconnecting from mail server:\n$result"

  }

  return

}

/*****************************************************/

R-1841# mkdir flash:eem/

R-1841# copy ftp://10.0.0.3/Publico/mail2.tcl flash:eem/

R-1841#copy ftp://10.0.0.3/Publico/custom_smtp_lib.tcl flash:/eem/

R-1841#dir flash:eem/

Directory of flash:eem/

   11  -rw-         627  Dec 20 2013 16:36:16 -03:00  mail2.tcl

   12  -rw-       12421  Dec 20 2013 16:40:16 -03:00  custom_smtp_lib.tcl

64012288 bytes total (19165184 bytes free)

R-1841#dir

Directory of tmpsys:/eem_lib_user/

  138  -r--       12421                      custom_smtp_lib.tcl

  137  -r--         627                      mail2.tcl

conf t

no event manager directory user policy "flash:/eem/"

no event manager directory user library "flash:/eem/"

no event manager policy mail2.tcl

event manager directory user policy "flash:/eem/"

event manager directory user library "flash:/eem/"

event manager policy mail2.tcl

int lo0

no shut

OUTPUT:

%TRACKING-5-STATE: 1 list boolean or Down->Up

%HA_EM-6-LOG: mail2.tcl: unknown namespace in import pattern "::cisco::lib::my_smtp_send_email"

%HA_EM-6-LOG: mail2.tcl:     while executing

%HA_EM-6-LOG: mail2.tcl: "namespace import ::cisco::lib::my_smtp_send_email"

%HA_EM-6-LOG: mail2.tcl:     invoked from within

%HA_EM-6-LOG: mail2.tcl: "$slave eval $Contents"

%HA_EM-6-LOG: mail2.tcl:     (procedure "eval_script" line 7)

%HA_EM-6-LOG: mail2.tcl:     invoked from within

%HA_EM-6-LOG: mail2.tcl: "eval_script slave $scriptname"

%HA_EM-6-LOG: mail2.tcl:     invoked from within

%HA_EM-6-LOG: mail2.tcl: "if {$security_level == 1} {       #untrusted script

%HA_EM-6-LOG: mail2.tcl:      interp create -safe slave

%HA_EM-6-LOG: mail2.tcl:      interp share {} stdin slave

%HA_EM-6-LOG: mail2.tcl:      interp share {} stdout slave

%HA_EM-6-LOG: mail2.tcl: ..."

%HA_EM-6-LOG: mail2.tcl:     (file "tmpsys:/lib/tcl/base.tcl" line 50)

%HA_EM-6-LOG: mail2.tcl: Tcl policy execute failed:

%HA_EM-6-LOG: mail2.tcl: unknown namespace in import pattern "::cisco::lib::my_smtp_send_email"

Cisco Employee

Re: Send MAIL TCL not working

Don't change the namespaces in your policy.  Those should still be:

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*

Everything else looks right.

Highlighted
Community Member

Re: Send MAIL TCL not working

We are almost there:

no event manager directory user policy "flash:/eem/"

no event manager directory user library "flash:/eem/"

no event manager policy mail2.tcl

event manager directory user policy "flash:/eem/"

event manager directory user library "flash:/eem/"

event manager policy mail2.tcl

int lo0

no shut

Now I have this output:

%TRACKING-5-STATE: 98 ip sla 98 state Down->Up

%TRACKING-5-STATE: 1 list boolean or Down->Up

%HA_EM-6-LOG: mail2.tcl: invalid command name "my_smtp_send_email"

%HA_EM-6-LOG: mail2.tcl:     while executing

%HA_EM-6-LOG: mail2.tcl: "my_smtp_send_email $mail_msg"

%HA_EM-6-LOG: mail2.tcl:     invoked from within

%HA_EM-6-LOG: mail2.tcl: "$slave eval $Contents"

%HA_EM-6-LOG: mail2.tcl:     (procedure "eval_script" line 7)

%HA_EM-6-LOG: mail2.tcl:     invoked from within

%HA_EM-6-LOG: mail2.tcl: "eval_script slave $scriptname"

%HA_EM-6-LOG: mail2.tcl:     invoked from within

%HA_EM-6-LOG: mail2.tcl: "if {$security_level == 1} {       #untrusted script

%HA_EM-6-LOG: mail2.tcl:      interp create -safe slave

%HA_EM-6-LOG: mail2.tcl:      interp share {} stdin slave

%HA_EM-6-LOG: mail2.tcl:      interp share {} stdout slave

%HA_EM-6-LOG: mail2.tcl: ..."

%HA_EM-6-LOG: mail2.tcl:     (file "tmpsys:/lib/tcl/base.tcl" line 50)

%HA_EM-6-LOG: mail2.tcl: Tcl policy execute failed:

%HA_EM-6-LOG: mail2.tcl: invalid command name "my_smtp_send_email"

This is the mail2.tcl now:

R-1841#more flash:eem/mail2.tcl

::cisco::eem::event_register_syslog occurs 1 pattern ".*1 list boolean or.*"

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*

set mail_pre "Mailservername: marcelo@xxx.com.br:xxx@177.73.xxx.xxx\n"

append mail_pre "From: marcelo@xxx.com.br\n"

append mail_pre "To: xxx@gmail.com\n"

append mail_pre "Cc: \n"

append mail_pre "Subject: Link Virtua DOWN\n"

append mail_pre "Teste\n\n"

set mail_msg [uplevel #0 [list subst -nobackslashes -nocommands $mail_pre]]

if [catch {my_smtp_send_email $mail_msg} result] {

    error $result $errorInfo

}

Cisco Employee

Re: Send MAIL TCL not working

Try this version and the accompanying tclIndex file (both need to go in your user library directory).  Then add the following import to your policy:

namespace import ::custom::lib::*

Community Member

Re: Send MAIL TCL not working

I got this now:

Directory of flash:/eem/

   11  -rw-         662  Dec 20 2013 18:44:00 -03:00  mail2.tcl

   12  -rw-        8893  Dec 20 2013 18:42:26 -03:00  custom_smtp_lib.tcl

   13  -rw-         625  Dec 20 2013 18:42:02 -03:00  tclIndex

R-1841#more flash:eem/mail2.tcl

::cisco::eem::event_register_syslog occurs 1 pattern ".*1 list boolean or.*"

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*

namespace import ::custom::lib::*

set mail_pre "Mailservername: marcelo@xxx.com.br:xxx@177.73.xxx.xxx\n"

append mail_pre "From: marcelo@xxx.com.br\n"

append mail_pre "To: xxx@gmail.com\n"

append mail_pre "Cc: \n"

append mail_pre "Subject: Link Virtua DOWN\n"

append mail_pre "Teste\n\n"

set mail_msg [uplevel #0 [list subst -nobackslashes -nocommands $mail_pre]]

if [catch {my_smtp_send_email $mail_msg} result] {

    error $result $errorInfo

}

no event manager directory user policy "flash:/eem/"

no event manager directory user library "flash:/eem/"

no event manager policy mail2.tcl

event manager directory user policy "flash:/eem/"

event manager directory user library "flash:/eem/"

event manager policy mail2.tcl

int lo0

no shut

: %LINK-3-UPDOWN: Interface Loopback0, changed state to up

: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback0, changed state to up

: %TRACKING-5-STATE: 98 ip sla 98 state Down->Up

: %TRACKING-5-STATE: 1 list boolean or Down->Up

: %HA_EM-6-LOG: mail2.tcl: error connecting to mail server:

: %HA_EM-6-LOG: mail2.tcl: Process Forced Exit- MAXRUN timer expired.

: %HA_EM-6-LOG: mail2.tcl:     while executing

: %HA_EM-6-LOG: mail2.tcl: "my_smtp_send_email $mail_msg"

: %HA_EM-6-LOG: mail2.tcl:     invoked from within

: %HA_EM-6-LOG: mail2.tcl: "$slave eval $Contents"

: %HA_EM-6-LOG: mail2.tcl:     (procedure "eval_script" line 7)

: %HA_EM-6-LOG: mail2.tcl:     invoked from within

: %HA_EM-6-LOG: mail2.tcl: "eval_script slave $scriptname"

: %HA_EM-6-LOG: mail2.tcl:     invoked from within

: %HA_EM-6-LOG: mail2.tcl: "if {$security_level == 1} {       #untrusted script

: %HA_EM-6-LOG: mail2.tcl:      interp create -safe slave

: %HA_EM-6-LOG: mail2.tcl:      interp share {} stdin slave

: %HA_EM-6-LOG: mail2.tcl:      interp share {} stdout slave

: %HA_EM-6-LOG: mail2.tcl: ..."

: %HA_EM-6-LOG: mail2.tcl:     (file "tmpsys:/lib/tcl/base.tcl" line 50)

: %HA_EM-6-LOG: mail2.tcl: Tcl policy execute failed:

: %HA_EM-6-LOG: mail2.tcl: error connecting to mail server:

: %HA_EM-6-LOG: mail2.tcl: Process Forced Exit- MAXRUN timer expired.

Cisco Employee

Re: Send MAIL TCL not working

This means that the router is having issues establishing a TCP connection to port 587 on your mail server.  From the router itself, can you telnet to port 587 on that server?

1586
Views
0
Helpful
25
Replies
CreatePlease to create content