How To Send MIME Attachments Using EEM

Document

Sat, 10/03/2015 - 12:35
Mar 31st, 2010

It is very easy to send email messages using EEM.  Often times, it is sufficient to simply include CLI output or other messages in the body of the email.  However, some output may be quite large, or you may have a need to send binary attachments (e.g. Embedded Packet Capture files).  In those cases, it would be better to use MIME encoding, and add the data as file attachments.  Here is a short proof-of-concept EEM script that demonstrates how to do this.

::cisco::eem::register_event_none

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*

# First, create the headers and body of your message

set email_body_pre "Mailservername: $_email_server
From: $_email_from
To: $_email_to
Cc:
Subject: Email from Router $_router_name
MIME-Version: 1.0
Content-type: multipart/mixed; boundary=\"EEM_email_boundary\"
\n--EEM_email_boundary\n
\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test.log\"\n\n"

# Then, read in the data you wish to attach.

if [catch {open "flash:test.log"} result] {
    error $result $errorInfo
}
set fd $result

# Encode that data using the built-in base64 library.
set email_b64 [::base64::encode [read $fd]]
close $fd

# Construct the final message with the headers, body, and MIME parts.

set email_body_mime "\n--EEM_email_boundary--"

set email_body [format "%s%s%s" $email_body_pre $email_b64 $email_body_mime]

# Send the email.

if [catch {smtp_send_email $email_body} result] {
    error $result $errorInfo
}

ideocisco Fri, 10/02/2015 - 11:54

Hi,

 

What if you need to send 2 attachments and add text in the body of the email?

 

Thanks,

Stéphane

Joe Clarke Fri, 10/02/2015 - 11:58

You just need to add more boundaries (i.e. more EEM_email_boundary sections).  The text body will come between the first two in $email_body_pre.

ideocisco Fri, 10/02/2015 - 12:02

Thanks for your fast response.

I am new to this, so please forgive my lack of knowledge.

Is this what you mean :

MIME-Version: 1.0
Content-type: multipart/mixed; boundary=\"EEM_email_boundary\"
\n--EEM_email_boundary\n
This is a test to appear in the body of the message
\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test.log\"\n\n"
\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test2.log\"\n\n"

Thanks,

Stéphane

ideocisco Fri, 10/02/2015 - 13:47

Hi,

Thanks this works perfectly nice.
Another question.
What if I wanted to attach text already in a variable. Is this possible?

Ex :
set email_attachment_1 "This is a test"
Content-Disposition: attachment; filename=\"Message.txt\"\n\n"
set email_b64 [::base64::encode [$email_attachment_1]]

Thanks,

Stéphane

ideocisco Fri, 10/02/2015 - 13:55

I get the following error :

Router#event manager run Test.tcl

invalid command name "
 Pool Tag: 21
 MAC Address                : AAAA.AAAA.AAAA
 No. of attempts to register: 0
 Unregister time            :
 Last register request time :
 Reason for state unregister:
         No registration request since last reboot/unregister

 Pool Tag: 22
 MAC Address                : BBBB.BBBB.BBBB
 No. of attempts to register: 0
 Unregister time            :
 Last register request time :
 Reason for state unregister:
         No registration request since last reboot/unregister

Router#"

    while executing
"$email_attachment_1"
    invoked from within
"if {$ata_down} {
  append email_pre "$msg"

  app..."
    (file "tmpsys:/eem_policy/Test.tcl" line 179)
Tcl policy execute failed: invalid command name "
 Pool Tag: 21
 MAC Address                : AAAA.AAAA.AAAA
 No. of attempts to register: 0
 Unregister time            :

 Last register request time :
 Reason for state unregister:
         No registration request since last reboot/unregister

 Pool Tag: 22
 MAC Address                : BBBB.BBBB.BBBB
 No. of attempts to register: 0
 Unregister time            :
 Last register request time :
 Reason for state unregister:
         No registration request since last reboot/unregister

 

$email_attachment_1 contains the following :

 Pool Tag: 21
 MAC Address                : AAAA.AAAA.AAAA
 No. of attempts to register: 0
 Unregister time            :
 Last register request time :
 Reason for state unregister:
         No registration request since last reboot/unregister

 Pool Tag: 22
 MAC Address                : BBBB.BBBB.BBBB
 No. of attempts to register: 0
 Unregister time            :
 Last register request time :
 Reason for state unregister:
         No registration request since last reboot/unregister

Joe Clarke Fri, 10/02/2015 - 14:16

You can't put brackets around your variable.  It should be:

set email_b64 [::base64::encode $email_attachment_1]

 

ideocisco Fri, 10/02/2015 - 15:40

Thank you Joseph.

You are truly the best contributer I have the please to chat with.

This is working like a charm.

Thanks,

Stéphane

ideocisco Sat, 10/03/2015 - 10:54

Hi,

When I try to have 2 attachments, I do not get the results expected. The first attachment is empty and the 2nd attachment contains the data of the 2 files.

Here is my code :

set email_pre "Mailservername: $_email_server
From: $_email_from
To: $_email_to
Cc:
Subject: Test 2 attachment
MIME-Version: 1.0
Content-type: multipart/mixed; boundary=\"EEM_email_boundary\"
\n--EEM_email_boundary\n
This is a test email with 2 attachments"
append email_pre "\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test.log\"\n\n"

if [catch {open "flash:test.log"} result] {
    error $result $errorInfo
}
set fd $result
set email_b64 [::base64::encode [read $fd]]
close $fd

append email_pre "\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test2.log\"\n\n"

if [catch {open "flash:test2.log"} result] {
    error $result $errorInfo
}
set fd $result
set email_b64_2 [::base64::encode [read $fd]]
close $fd

set email_body_mime "\n--EEM_email_boundary--"
set email_body [format "%s%s%s" $email_pre $email_b64 $email_b64_2 $email_body_mime]

if [catch {smtp_send_email $email_body} result] {
    error $result $errorInfo
}

Joe Clarke Sat, 10/03/2015 - 11:13

You need to have the boundaries between your attachments.  Appending another boundary to email_pre doesn't do you any good.  Best to gave email_pre be your initial headers and email body.  Then each attachment will start its boundary and MIME info.

ideocisco Sat, 10/03/2015 - 11:24

Hi,

Don't I have boudaries between my attachments :

append email_pre "\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test.log\"\n\n"

append email_pre "\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test2.log\"\n\n"

Joe Clarke Sat, 10/03/2015 - 11:27

No, because $email_pre is only included at the front of you email.  You construct the email as:

 

email_pre

email_b64

email_b64_2

email_body_mime

 

You need a boundary and MIME header before email_b64 and before email_b64_2.

ideocisco Sat, 10/03/2015 - 11:40

Hi,

So something like :
set email_pre2 "MIME-Version: 1.0
Content-type: multipart/mixed; boundary=\"EEM_email_boundary\"
\n--EEM_email_boundary\n
\n--EEM_email_boundary
Content-Type: application/octet-stream
Content-Transfer-Encoding: Base64
Content-Disposition: attachment; filename=\"test2.log\"\n\n"

set email_body_mime "\n--EEM_email_boundary--"
set email_body [format "%s%s%s%s%s%s" $email_pre $email_b64 $email_body_mime $email_pre2 $email_b64_2 $email_body_mime]

 

ideocisco Sat, 10/03/2015 - 11:35

Hi,

I am getting there.

The above code sends me three attachments.
The 2 log files and the Body message both in the message and as an attachment.

ideocisco Sat, 10/03/2015 - 12:35

Hi,

I finally understand.


It is working.

This is what I did :

 

Thanks a lot for your help.

set email_body [format "%s%s%s%s%s%s%s" $email_pre $email_body $email_mime_1 $email_b64 $email_mime_2 $email_b64_2 $email_body_mime]

Joe Clarke Sat, 10/03/2015 - 11:40

No, because for starters you don't use email_pre2 anywhere.  What you need to do is prepend the header to each MIME attachment.  So, you can do:

 

set mimeh "\n--EEM_email_boundary

Content-Type: application/octet-stream

Content-Transfer-Encoding: Base64"

 

Then append the final line for the file name each time you need it:

 

set mime1 $mimeh

append mime1 "Content-Disposition: attachment; filename=\"test.log\"\n\n"

set mime2 $mimeh

append mime2 "Content-Disposition: attachment; filename=\"test2.log\"\n\n"

 

Then construct your email using:

 

email_pre

mime1

email_b4

mime2

email_b64_2

email_body_mime

Actions

This Document

Related Content