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 == '':