RAPP Platform  v0.6.0
RAPP Platform is a collection of ROS nodes and back-end processes that aim to deliver ready-to-use generic services to robots
 All Classes Namespaces Files Functions Variables Macros
email_sender.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- encode: utf-8 -*-
3 
4 #Copyright 2015 RAPP
5 
6 #Licensed under the Apache License, Version 2.0 (the "License");
7 #you may not use this file except in compliance with the License.
8 #You may obtain a copy of the License at
9 
10  #http://www.apache.org/licenses/LICENSE-2.0
11 
12 #Unless required by applicable law or agreed to in writing, software
13 #distributed under the License is distributed on an "AS IS" BASIS,
14 #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 #See the License for the specific language governing permissions and
16 #limitations under the License.
17 
18 # Authors: Aris Thallas
19 # contact: aris.thallas@{iti.gr, gmail.com}
20 
21 import os
22 import smtplib
23 import socket
24 import mimetypes
25 from email import encoders
26 from email.mime.text import MIMEText
27 from email.mime.multipart import MIMEMultipart
28 from email.mime.audio import MIMEAudio
29 from email.mime.image import MIMEImage
30 from email.mime.base import MIMEBase
31 
32 import rospy
33 
34 from rapp_utilities import RappUtilities
35 
36 from rapp_platform_ros_communications.srv import (
37  SendEmailSrv,
38  SendEmailSrvResponse
39  )
40 
41 class EmailSender(object):
42 
43  def __init__(self):
44  sendSrvTopic = rospy.get_param("rapp_email_send_topic")
45  sendSrv = rospy.Service(sendSrvTopic, SendEmailSrv, \
47 
48  ## The callback to send specified mails from users email account
49  #
50  # @rapam req [rapp_platform_ros_communications::Email::SendEmailSrvRequest] The send email request
51  #
52  # @rapam res [rapp_platform_ros_communications::Email::SendEmailSrvResponse] The send email response
53  def sendEmailSrvCallback(self, req):
54 
55  resp = SendEmailSrvResponse()
56 
57  RappUtilities.rapp_print(req, 'DEBUG')
58 
59  if len(req.recipients) == 0:
60  RappUtilities.rapp_print("Must provide at least one recipient", 'ERROR')
61  resp.status = -1
62  return resp
63 
64  msg = self._createEmailBody( \
65  req.recipients, req.userEmail, req.body, req.subject )
66 
67  for attachment in req.files:
68  try:
69  attach = self._handleAttachment( attachment )
70  except EnvironmentError, err:
71  RappUtilities.rapp_print("Failed to handle attachment: " + attachment, \
72  'ERROR')
73  RappUtilities.rapp_print(err, 'ERROR')
74  resp.status = -1
75  return resp
76  else:
77  msg.attach( attach )
78 
79  try:
80  self._connectAndSend( req.userEmail, req.password, req.recipients, \
81  req.server, req.port, msg )
82  except (socket.error, smtplib.SMTPException):
83  resp.status = -1
84  return resp
85 
86  resp.status = 0
87  return resp
88 
89 
90  ## Connect to the requested SMTP server and send email
91  #
92  # @param userEmail [string] The sender's email
93  # @param userPassword [string] The sender's password
94  # @param recipients [list<string>] The recipients' emails
95  # @param server [string] The SMTP server's address
96  # @param port [string] The SMTP server's port
97  #
98  # @exception smtplib.SMTPException Base SMTP exception class
99  # @exception socket.error Socket class exception (connection problem)
100  def _connectAndSend(self, userEmail, userPassword, recipients, server, port, msg):
101  RappUtilities.rapp_print( "Connecting to the requested SMTP server: " + \
102  server + ' port: ' + port)
103  try:
104  socket.setdefaulttimeout(5)
105  if port is not None and port != '':
106  smtpServer = smtplib.SMTP(server, port)
107  else:
108  smtpServer = smtplib.SMTP(server)
109  except socket.error, err:
110  RappUtilities.rapp_print( \
111  "Could not establish a connection to the requested SMTP server: " + \
112  server + ' port: ' + port, 'ERROR')
113  RappUtilities.rapp_print( err, 'ERROR')
114  raise err
115 
116  try:
117  smtpServer.ehlo()
118  smtpServer.starttls()
119  smtpServer.ehlo()
120  smtpServer.login( userEmail, userPassword )
121  smtpServer.sendmail( userEmail, recipients, msg.as_string() )
122  except smtplib.SMTPException, err:
123  RappUtilities.rapp_print( "SMTP failed!", 'ERROR')
124  RappUtilities.rapp_print( err, 'ERROR')
125  raise err
126  finally:
127  smtpServer.quit()
128 
129  ## Creates the emails main body
130  #
131  # @param recipients [list<string>] The recipients' emails
132  # @param userEmail [string] The sender's email
133  # @param subject [string] The email's subject
134  # @param body [string] The email's body text
135  #
136  # @return msg [MimeMultipart] The email's main body to be sent via SMTP
137  def _createEmailBody( self, recipients, userEmail, body, subject ):
138 
139  if subject == '' or subject is None:
140  RappUtilities.rapp_print('No email subject provided')
141  msg = MIMEMultipart()
142  msg['Subject'] = subject
143  msg['From'] = userEmail
144  msg['To'] = ', '.join( recipients )
145  if body == '' or body is None:
146  RappUtilities.rapp_print('No email body provided')
147  msg.attach( MIMEText(body) )
148  return msg
149 
150  ## Add attachment to the email
151  #
152  # @param filename [string] The absolute path of the requested file
153  #
154  # @return attachment [mimeobject] The attachment format of the file to be appended to the email
155  #
156  # @exception IOError General IO error
157  # @exception EnvironmentError General IO error
158  def _handleAttachment( self, filename ):
159  #TODO: sanitize paths
160 
161  if not os.path.isfile( filename ):
162  raise IOError('Filename does not exist! ' + filename)
163 
164  fp = open( filename , 'rb')
165  filetype, encoding = mimetypes.guess_type( fp.name )
166  if filetype is None or encoding is not None:
167  filetype = 'application/octet-stream'
168  maintype, subtype = filetype.split('/', 1)
169 
170  RappUtilities.rapp_print('Attachment : ' + filename )
171  RappUtilities.rapp_print('Attachment maintype: ' + maintype + ' subtype: ' +\
172  subtype)
173  if maintype == 'text':
174  attachment = MIMEText( fp.read(), _subtype=subtype )
175  elif maintype == 'image':
176  attachment = MIMEImage( fp.read(), _subtype=subtype )
177  elif maintype == 'audio':
178  attachment = MIMEAudio( fp.read(), _subtype=subtype )
179  else:
180  attachment = MIMEBase( maintype, subtype )
181  attachment.set_payload( fp.read() )
182  encoders.encode_base64( attachment )
183 
184  fp.close()
185 
186  attachment.add_header( 'Content-Disposition',\
187  'attachment', filename = os.path.basename(filename) )
188  return attachment
189 
190 if __name__ == '__main__':
191  print('Implements server for EmailSendSrv. Not supposed to' + \
192  ' be called directly')
193  exit(-1)
def _handleAttachment
Add attachment to the email.
def sendEmailSrvCallback
The callback to send specified mails from users email account.
Definition: email_sender.py:53
def _createEmailBody
Creates the emails main body.
def _connectAndSend
Connect to the requested SMTP server and send email.