diff --git a/jsk_robot_common/jsk_robot_startup/CMakeLists.txt b/jsk_robot_common/jsk_robot_startup/CMakeLists.txt
index aace5914cb..4268264cca 100644
--- a/jsk_robot_common/jsk_robot_startup/CMakeLists.txt
+++ b/jsk_robot_common/jsk_robot_startup/CMakeLists.txt
@@ -59,6 +59,7 @@ add_message_files(
FILES
RoomLight.msg
Email.msg
+ EmailBody.msg
)
generate_messages(
diff --git a/jsk_robot_common/jsk_robot_startup/euslisp/email-topic-client.l b/jsk_robot_common/jsk_robot_startup/euslisp/email-topic-client.l
index a78d46de09..8def28a2ff 100644
--- a/jsk_robot_common/jsk_robot_startup/euslisp/email-topic-client.l
+++ b/jsk_robot_common/jsk_robot_startup/euslisp/email-topic-client.l
@@ -1,5 +1,7 @@
(ros::load-ros-manifest "jsk_robot_startup")
+(require :base64 "lib/llib/base64.l")
+
(defun init-mail ()
(ros::advertise "email" jsk_robot_startup::Email 1)
(ros::spin-once)
@@ -16,7 +18,23 @@
(setq msg (instance jsk_robot_startup::Email :init))
(send msg :header :stamp (ros::time-now))
(send msg :subject subject)
- (send msg :body body)
+ (send msg :body
+ (mapcar #'(lambda (e)
+ (cond ((derivedp e image-2d)
+ (if (> (length (send e :entity)) (* 8 8192))
+ (warning-message 3 "The size of img is too large (~A)~%You may encounter 'too long string' error, see https://github.com/euslisp/EusLisp/issues/2 for more info~%" (length (send e :entity))))
+ (instance jsk_robot_startup::EmailBody :init :type "img"
+ :img_data (base64encode (send e :entity))
+ :img_size 100))
+ ((probe-file e)
+ (instance jsk_robot_startup::EmailBody :init :type "img" :file_path e :img_size 100))
+ ((and (> (length e) 0) ;; check html
+ (eq (elt e 0) #\<)
+ (eq (elt e (1- (length e))) #\>))
+ (instance jsk_robot_startup::EmailBody :init :type "html" :message e))
+ (t
+ (instance jsk_robot_startup::EmailBody :init :type "text" :message (format nil "~A" e)))))
+ (if (atom body) (list body) body)))
(send msg :sender_address sender-address)
(send msg :receiver_address receiver-address)
(send msg :smtp_server smtp-server)
diff --git a/jsk_robot_common/jsk_robot_startup/euslisp/sample-email-topic-client.l b/jsk_robot_common/jsk_robot_startup/euslisp/sample-email-topic-client.l
index 855b5f9fef..ad280eca65 100755
--- a/jsk_robot_common/jsk_robot_startup/euslisp/sample-email-topic-client.l
+++ b/jsk_robot_common/jsk_robot_startup/euslisp/sample-email-topic-client.l
@@ -7,10 +7,36 @@
(ros::spin-once)
(setq receiver-address (ros::get-param "~receiver_address"))
(setq attached-files (ros::get-param "~attached_files" nil))
-(unix::sleep 10) ;; wait for server
+(while (or (null (ros::get-num-subscribers "email"))
+ (<= (ros::get-num-subscribers "email") 0))
+ (ros::ros-warn "wait for email topic")
+ (unix::sleep 1))
(ros::ros-info "Sending a mail to ~A" receiver-address)
-(send-mail "test-mail" receiver-address "test" :attached-files attached-files)
-(ros::ros-info "Sent a mail")
+(send-mail "test text mail" receiver-address "test")
+(ros::ros-info "Sent a text mail")
+(unix:sleep 1)
+
+(send-mail "test html mail" receiver-address "
test with html mail
")
+(ros::ros-info "Sent a html mail")
+(unix:sleep 1)
+
+(send-mail "test attached mail" receiver-address "test with attached image" :attached-files attached-files)
+(ros::ros-info "Sent a mail with attached files ~A" attached-files)
+(unix:sleep 1)
+
+(when attached-files
+ (send-mail "test image embedded mail (file)" receiver-address (append attached-files (list "test with embedded image")))
+ (ros::ros-info "sent a mail with embedded image ~a" attached-files)
+ (unix:sleep 1)
+ ;; read png/jpeg file, but do not extract to raw image, keep original compressed data in (img . entity)
+ (setq img (read-image-file (elt attached-files 0)))
+ (setq (img . entity) (make-string (elt (unix:stat (elt attached-files 0)) 7))) ;; size of file
+ (with-open-file (f (elt attached-files 0)) (unix:uread (send f :infd) (img . entity)))
+ (send-mail "test image embedded mail (string)" receiver-address (list "test with embedded image" img))
+ (ros::ros-info "Sent a mail with embedded image ~A" img)
+ (unix:sleep 1)
+ )
+
(ros::roseus "shutdown")
(exit)
diff --git a/jsk_robot_common/jsk_robot_startup/msg/Email.msg b/jsk_robot_common/jsk_robot_startup/msg/Email.msg
index 5726aa1477..08cc108e30 100644
--- a/jsk_robot_common/jsk_robot_startup/msg/Email.msg
+++ b/jsk_robot_common/jsk_robot_startup/msg/Email.msg
@@ -1,6 +1,6 @@
std_msgs/Header header
string subject # Email subject
-string body # Email body
+jsk_robot_startup/EmailBody[] body # Email body
string sender_address # Sender's email address
string receiver_address # receiver's email address
string smtp_server # smtp server address
diff --git a/jsk_robot_common/jsk_robot_startup/msg/EmailBody.msg b/jsk_robot_common/jsk_robot_startup/msg/EmailBody.msg
new file mode 100644
index 0000000000..db3626ff0a
--- /dev/null
+++ b/jsk_robot_common/jsk_robot_startup/msg/EmailBody.msg
@@ -0,0 +1,5 @@
+string type # text, html, img
+string message # For text and html type
+string file_path # For img type, set file path
+string img_data # For img type, you can also use base64 encoded image data instead of file path
+uint8 img_size # For img type [percent]
diff --git a/jsk_robot_common/jsk_robot_startup/scripts/email_topic.py b/jsk_robot_common/jsk_robot_startup/scripts/email_topic.py
index 9918e174d8..4ec7f06f5b 100755
--- a/jsk_robot_common/jsk_robot_startup/scripts/email_topic.py
+++ b/jsk_robot_common/jsk_robot_startup/scripts/email_topic.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
from email.mime.application import MIMEApplication
+from email.mime.image import MIMEImage
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import errno
@@ -12,6 +13,9 @@
import socket
from socket import error as socket_error
import yaml
+import copy
+import random, string # for image cid
+import base64
class EmailTopic(object):
@@ -43,7 +47,11 @@ def __init__(self):
'email', Email, self._cb, queue_size=1)
def _cb(self, msg):
- rospy.loginfo('Received an msg: {}'.format(msg))
+ msg_compact = copy.deepcopy(msg)
+ for content in msg_compact.body:
+ if len(content.img_data) >= 64:
+ content.img_data = content.img_data[:64] + "...."
+ rospy.loginfo('Received an msg: {}'.format(msg_compact))
send_mail_args = {}
# Set default value for self._send_mail arguments
send_mail_args['subject'] = ''
@@ -75,7 +83,39 @@ def _send_mail(
msg["Subject"] = subject
msg["From"] = sender_address
msg["To"] = receiver_address
- msg.attach(MIMEText(body, 'plain', 'utf-8'))
+ # Support embed image
+ for content in body:
+ if content.type == 'text':
+ msg.attach(MIMEText(content.message, 'plain', 'utf-8'))
+ elif content.type == 'html':
+ msg.attach(MIMEText(content.message, 'html'))
+ elif content.type == 'img':
+ if content.img_data != '':
+ embed_img = MIMEImage(base64.b64decode(content.img_data))
+ cid = ''.join(random.choice(string.ascii_lowercase) for i in range(16))
+ elif os.path.exists(content.file_path):
+ with open(content.file_path, 'rb') as img:
+ embed_img = MIMEImage(img.read())
+ cid = content.file_path
+ else:
+ rospy.logerr("'img' content requries either file_path {}".format(content.type))
+ rospy.logerr(" or img_data {} with img_format {}".format(content.img_data, content.img_format))
+ continue
+ embed_img.add_header(
+ 'Content-ID', '<{}>'.format(cid))
+ embed_img.add_header(
+ 'Content-Disposition', 'inline; filename="{}"'.format(os.path.basename(cid)))
+ msg.attach(embed_img) # This line is necessary to embed
+ if content.img_size:
+ image_size = content.img_size
+ else:
+ image_size = 100
+ text = '
'.format(cid, image_size)
+ bodytext = MIMEText(text, 'html')
+ msg.attach(bodytext)
+ else:
+ rospy.logwarn('Unknown content type {}'.format(content.type))
+ continue
# Attach file
for attached_file in attached_files:
if attached_file == '':