docs: def sendEmail(sender,
                recipients,
                subject,
                body,
                attachments=None,
                cc=None,
                bcc=None,
                contentType='text/html',
                server=None,
                useMSExchange=None,
                encoding='utf-8',
                raiseErrors=False):
      """
      Sends an email from the inputted email address to the
      list of given recipients with the inputted subject and
      body.  This will also attach the inputted list of
      attachments to the email.  The server value will default 
      to mail.<sender_domain> and you can use a ':' to specify 
      a port for the server.
      
      :param      sender          <str>
      :param      recipients      <list> [ <str>, .. ]
      :param      subject         <str>
      :param      body            <str>
      :param      attachments     <list> [ <str>, .. ]
      :param      cc              <list> [ <str>, .. ]
      :param      bcc             <list> [ <str>, .. ]
      :param      contentType     <str>
      :param      server          <str>
      
      :return     <bool> success
      """
      if attachments is None:
          attachments = []
      if cc is None:
          cc = []
      if bcc is None:
          bcc = []
  
      if server is None:
          server = NOTIFY_SERVER
      if useMSExchange is None:
          useMSExchange = NOTIFY_SERVER_MSX
  
      # normalize the data
      sender = nstr(sender)
      recipients = map(nstr, recipients)
  
      # make sure we have valid information
      if not isEmail(sender):
          err = errors.NotifyError('%s is not a valid email address' % sender)
          logger.error(err)
          return False
  
      # make sure there are recipients
      if not recipients:
          err = errors.NotifyError('No recipients were supplied.')
          logger.error(err)
          return False
  
      # build the server domain
      if not server:
          err = errors.NotifyError('No email server specified')
          logger.error(err)
          return False
  
      # create the email
      msg = MIMEMultipart(_subtype='related')
      msg['Subject'] = projex.text.toUtf8(subject)
      msg['From'] = sender
      msg['To'] = ','.join(recipients)
      msg['Cc'] = ','.join([nstr(addr) for addr in cc if isEmail(addr)])
      msg['Bcc'] = ','.join([nstr(addr) for addr in bcc if isEmail(addr)])
      msg['Date'] = nstr(datetime.datetime.now())
      msg['Content-type'] = 'Multipart/mixed'
  
      msg.preamble = 'This is a multi-part message in MIME format.'
      msg.epilogue = ''
  
      # build the body
      bodyhtml = projex.text.toUtf8(body)
      eattach = []
  
      # include inline images
      filepaths = re.findall('<img\s+src="(file:///[^"]+)"[^/>]*/?>', bodyhtml)
      for filepath in filepaths:
          filename = filepath.replace('file:///', '')
          if os.path.exists(filename) and filename not in attachments:
              # replace with the attachment id
              cid = 'cid:%s' % os.path.basename(filename)
              bodyhtml = bodyhtml.replace(filename, cid)
  
              # add the image to the attachments
              fp = open(nstr(filename), 'rb')
              msgImage = MIMEImage(fp.read())
              fp.close()
  
              # add the msg image to the msg
              content_id = '<%s>' % os.path.basename(filename)
              inline_link = 'inline; filename="%s"' % os.path.basename(filename)
              msgImage.add_header('Content-ID', content_id)
              msgImage.add_header('Content-Disposition', inline_link)
  
              eattach.append(msgImage)
              attachments.append(filename)
  
      # create the body text
      msgText = MIMEText(bodyhtml, contentType, encoding)
      msgText['Content-type'] = contentType
  
      # include attachments
      for attach in attachments:
          fp = open(nstr(attach), 'rb')
          txt = MIMEBase('application', 'octet-stream')
          txt.set_payload(fp.read())
          fp.close()
  
          encode_base64(txt)
          attachment = 'attachment; filename="%s"' % os.path.basename(attach)
          txt.add_header('Content-Disposition', attachment)
          eattach.append(txt)
  
      eattach.insert(0, msgText)
  
      # add the attachments to the message
      for attach in eattach:
          msg.attach(attach)
  
      # create the connection to the email server
      try:
          smtp_server = smtplib.SMTP(nstr(server))
      except socket.gaierror, err:
          logger.error(err)
          if raiseErrors:
              raise
          return False
      except Exception, err:
          logger.error(err)
          if raiseErrors:
              raise
          return False
  
      # connect to a microsoft exchange server if specified
      if useMSExchange:
          success, response = connectMSExchange(smtp_server)
          if not success:
              logger.debug('Could not connect to MS Exchange: ' + response)
  
      try:
          smtp_server.sendmail(sender, recipients, msg.as_string())
          smtp_server.close()
      except Exception, err:
          logger.error(err)
          if raiseErrors:
              raise
          return False
  
      return True