def testProcessMail_MsgTooBig(self): self.mox.StubOutWithMock(emailfmt, 'IsBodyTooBigToParse') emailfmt.IsBodyTooBigToParse(mox.IgnoreArg()).AndReturn(True) self.mox.ReplayAll() email_tasks = self.inbound.ProcessMail(self.msg, self.project_addr) self.mox.VerifyAll() self.assertEquals(1, len(email_tasks)) email_task = email_tasks[0] self.assertEquals('*****@*****.**', email_task['to']) self.assertEquals('Email body too long', email_task['subject'])
def ProcessMail(self, msg, project_addr): """Process an inbound email message.""" # TODO(jrobbins): If the message is HUGE, don't even try to parse # it. Silently give up. (from_addr, to_addrs, cc_addrs, references, incident_id, subject, body) = emailfmt.ParseEmailMessage(msg) logging.info('Proj addr: %r', project_addr) logging.info('From addr: %r', from_addr) logging.info('Subject: %r', subject) logging.info('To: %r', to_addrs) logging.info('Cc: %r', cc_addrs) logging.info('References: %r', references) logging.info('Incident Id: %r', incident_id) logging.info('Body: %r', body) # If message body is very large, reject it and send an error email. if emailfmt.IsBodyTooBigToParse(body): return _MakeErrorMessageReplyTask( project_addr, from_addr, self._templates['body_too_long']) # Make sure that the project reply-to address is in the To: line. if not emailfmt.IsProjectAddressOnToLine(project_addr, to_addrs): return None project_name, verb, trooper_queue = emailfmt.IdentifyProjectVerbAndLabel( project_addr) is_alert = bool(verb and verb.lower() == 'alert') error_addr = from_addr local_id = None author_addr = from_addr if is_alert: error_addr = settings.alert_escalation_email author_addr = settings.alert_service_account else: local_id = emailfmt.IdentifyIssue(project_name, subject) if not local_id: logging.info('Could not identify issue: %s %s', project_addr, subject) # No error message, because message was probably not intended for us. return None cnxn = sql.MonorailConnection() if self.services.cache_manager: self.services.cache_manager.DoDistributedInvalidation(cnxn) project = self.services.project.GetProjectByName(cnxn, project_name) # Authenticate the author_addr and perm check. try: mc = monorailcontext.MonorailContext( self.services, cnxn=cnxn, requester=author_addr, autocreate=is_alert) mc.LookupLoggedInUserPerms(project) except exceptions.NoSuchUserException: return _MakeErrorMessageReplyTask( project_addr, error_addr, self._templates['no_account']) # TODO(zhangtiff): Add separate email templates for alert error cases. if not project or project.state != project_pb2.ProjectState.LIVE: return _MakeErrorMessageReplyTask( project_addr, error_addr, self._templates['project_not_found']) if not project.process_inbound_email: return _MakeErrorMessageReplyTask( project_addr, error_addr, self._templates['replies_disabled'], project_name=project_name) # Verify that this is a reply to a notification that we could have sent. is_development = os.environ['SERVER_SOFTWARE'].startswith('Development') if not (is_alert or is_development): for ref in references: if emailfmt.ValidateReferencesHeader(ref, project, from_addr, subject): break # Found a message ID that we could have sent. if emailfmt.ValidateReferencesHeader( ref, project, from_addr.lower(), subject): break # Also match all-lowercase from-address. else: # for-else: if loop completes with no valid reference found. return _MakeErrorMessageReplyTask( project_addr, from_addr, self._templates['not_a_reply']) # Note: If the issue summary line is changed, a new thread is created, # and replies to the old thread will no longer work because the subject # line hash will not match, which seems reasonable. if mc.auth.user_pb.banned: logging.info('Banned user %s tried to post to %s', from_addr, project_addr) return _MakeErrorMessageReplyTask( project_addr, error_addr, self._templates['banned']) # If the email is an alert, switch to the alert handling path. if is_alert: alert2issue.ProcessEmailNotification( self.services, cnxn, project, project_addr, from_addr, mc.auth, subject, body, incident_id, msg, trooper_queue) return None # This email is a response to an email about a comment. self.ProcessIssueReply( mc, project, local_id, project_addr, body) return None