def test_with_users(self): project = self.project user_a = User.objects.create(email='*****@*****.**') user_b = User.objects.create(email='*****@*****.**') user_c = User.objects.create(email='*****@*****.**') UserOption.objects.create( user=user_b, key='alert_email', value='*****@*****.**', ) UserOption.objects.create( user=user_c, project=project, key='mail:email', value='*****@*****.**', ) msg = MessageBuilder( subject='Test', body='hello world', html_body='<!DOCTYPE html>\n<b>hello world</b>', ) msg.add_users([user_a.id, user_b.id, user_c.id], project=project) msg.send() assert len(mail.outbox) == 3 assert sorted([out.to[0] for out in mail.outbox]) == [ '*****@*****.**', '*****@*****.**', '*****@*****.**', ]
def test_fake_dont_send(self): project = self.project user_a = User.objects.create(email=create_fake_email('foo', 'fake')) user_b = User.objects.create(email=create_fake_email('bar', 'fake')) user_c = User.objects.create(email=create_fake_email('baz', 'fake')) UserOption.objects.create( user=user_b, key='alert_email', value=create_fake_email('fizzle', 'fake'), ) UserOption.objects.create( user=user_c, project=project, key='mail:email', value=create_fake_email('bazzer', 'fake'), ) msg = MessageBuilder( subject='Test', body='hello world', html_body='<!DOCTYPE html>\n<b>hello world</b>', ) msg.add_users([user_a.id, user_b.id, user_c.id], project=project) msg.send() assert len(mail.outbox) == 0
def test_with_users(self): project = self.project user_a = User.objects.create(email="*****@*****.**") user_b = User.objects.create(email="*****@*****.**") user_c = User.objects.create(email="*****@*****.**") UserOption.objects.create(user=user_c, project=project, key="mail:email", value="*****@*****.**") msg = MessageBuilder(subject="Test", body="hello world", html_body="<!DOCTYPE html>\n<b>hello world</b>") msg.add_users([user_a.id, user_b.id, user_c.id], project=project) msg.send() assert len(mail.outbox) == 3 assert sorted([out.to[0] for out in mail.outbox]) == [ "*****@*****.**", "*****@*****.**", "*****@*****.**", ]
def test_with_users(self): project = self.project user_a = User.objects.create(email='*****@*****.**') user_b = User.objects.create(email='*****@*****.**') user_c = User.objects.create(email='*****@*****.**') UserOption.objects.create( user=user_b, key='alert_email', value='*****@*****.**', ) UserOption.objects.create( user=user_c, project=project, key='mail:email', value='*****@*****.**', ) msg = MessageBuilder( subject='Test', body='hello world', html_body='<!DOCTYPE html>\n<b>hello world</b>', ) msg.add_users([user_a.id, user_b.id, user_c.id], project=project) msg.send() assert len(mail.outbox) == 3 assert sorted([out.to[0] for out in mail.outbox]) == [ '*****@*****.**', '*****@*****.**', '*****@*****.**', ]
def send_approved_email(self): from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { 'email': email, 'name': user.get_display_name(), 'organization': organization, 'team': self.team, } msg = MessageBuilder( subject='Sentry Access Request', template='sentry/emails/access-approved.txt', html_template='sentry/emails/access-approved.html', context=context, ) try: msg.send([email]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_sso_link_email(self): from sentry.utils.email import MessageBuilder context = { 'email': self.email, 'organization_name': self.organization.name, 'url': absolute_uri( reverse('sentry-auth-link-identity', kwargs={ 'organization_slug': self.organization.slug, })), } msg = MessageBuilder( subject='Action Required for %s' % (self.organization.name, ), template='sentry/emails/auth-link-identity.txt', html_template='sentry/emails/auth-link-identity.html', context=context, ) try: msg.send([self.get_email()]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_add_groupemailthread(self, make_msgid): make_msgid.return_value = 'abc123' msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.group, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Test', 'First message should not have Re: prefix' assert out.extra_headers['Message-Id'] == 'abc123' assert 'In-Reply-To' not in out.extra_headers assert 'References' not in out.extra_headers assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', ) # Our new EmailThread row was added assert GroupEmailThread.objects.count() == 1 thread = GroupEmailThread.objects.all()[0] assert thread.msgid == 'abc123' assert thread.email == '*****@*****.**' assert thread.group == self.group
def test_in_reply_to(self): msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.activity, reply_reference=self.group, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Re: Test' assert out.extra_headers[ 'Message-Id'] == '<activity/%s@localhost>' % self.activity.pk assert out.extra_headers[ 'In-Reply-To'] == '<group/%s@localhost>' % self.group.pk assert out.extra_headers[ 'References'] == '<group/%s@localhost>' % self.group.pk assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<b>hello world</b>', 'text/html', )
def send_approved_email(self): from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { 'email': email, 'name': user.get_display_name(), 'organization': organization, 'team': self.team, } msg = MessageBuilder( subject='Sentry Access Request', template='sentry/emails/access-approved.txt', html_template='sentry/emails/access-approved.html', context=context, ) try: msg.send([email]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_fake_dont_send(self): project = self.project user_a = User.objects.create(email=create_fake_email('foo', 'fake')) user_b = User.objects.create(email=create_fake_email('bar', 'fake')) user_c = User.objects.create(email=create_fake_email('baz', 'fake')) UserOption.objects.create( user=user_b, key='alert_email', value=create_fake_email('fizzle', 'fake'), ) UserOption.objects.create( user=user_c, project=project, key='mail:email', value=create_fake_email('bazzer', 'fake'), ) msg = MessageBuilder( subject='Test', body='hello world', html_body='<!DOCTYPE html>\n<b>hello world</b>', ) msg.add_users([user_a.id, user_b.id, user_c.id], project=project) msg.send() assert len(mail.outbox) == 0
def send_request_email(self): from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { 'email': email, 'name': user.get_display_name(), 'organization': organization, 'team': self.team, 'url': absolute_uri(reverse('sentry-organization-members', kwargs={ 'organization_slug': organization.slug, }) + '?ref=access-requests'), } msg = MessageBuilder( subject='Sentry Access Request', template='sentry/emails/request-team-access.txt', html_template='sentry/emails/request-team-access.html', context=context, ) try: msg.send([email]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_add_groupemailthread(self, make_msgid): make_msgid.return_value = "abc123" msg = MessageBuilder(subject="Test", body="hello world", html_body="<b>hello world</b>", reference=self.group) msg.send(["*****@*****.**"]) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ["*****@*****.**"] assert out.subject == "Test", "First message should not have Re: prefix" assert out.extra_headers["Message-Id"] == "abc123" assert "In-Reply-To" not in out.extra_headers assert "References" not in out.extra_headers assert out.body == "hello world" assert len(out.alternatives) == 1 assert out.alternatives[0] == ( "<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>", "text/html", ) # Our new EmailThread row was added assert GroupEmailThread.objects.count() == 1 thread = GroupEmailThread.objects.all()[0] assert thread.msgid == "abc123" assert thread.email == "*****@*****.**" assert thread.group == self.group
def test_add_groupemailthread(self, make_msgid): make_msgid.return_value = 'abc123' msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.group, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Test', 'First message should not have Re: prefix' assert out.extra_headers['Message-Id'] == 'abc123' assert 'In-Reply-To' not in out.extra_headers assert 'References' not in out.extra_headers assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', ) # Our new EmailThread row was added assert GroupEmailThread.objects.count() == 1 thread = GroupEmailThread.objects.all()[0] assert thread.msgid == 'abc123' assert thread.email == '*****@*****.**' assert thread.group == self.group
def send_invite_email(self): from sentry.utils.email import MessageBuilder context = { 'email': self.email, 'organization': self.organization, 'url': absolute_uri( reverse('sentry-accept-invite', kwargs={ 'member_id': self.id, 'token': self.token, })), } msg = MessageBuilder( subject='Invite to join organization: %s' % (self.organization.name, ), template='sentry/emails/member_invite.txt', context=context, ) try: msg.send([self.email]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def post(self, request, organization): """ Email the organization owners asking them to install an integration. ```````````````````````````````````````````````````````````````````` When a non-owner user views integrations in the integrations directory, they lack the ability to install them themselves. POSTing to this API alerts users with permission that there is demand for this integration. :param string providerSlug: Unique string that identifies the integration. :param string providerType: One of: first_party, plugin, sentry_app. :param string message: Optional message from the requester to the owners. """ provider_type = request.data.get("providerType") provider_slug = request.data.get("providerSlug") message_option = request.data.get("message", "").strip() try: provider_name = get_provider_name(provider_type, provider_slug) except RuntimeError as error: return Response({"detail": force_text(error)}, status=400) requester = request.user owners_list = organization.get_owners() # If for some reason the user had permissions all along, silently fail. if requester.id in [user.id for user in owners_list]: return Response({"detail": "User can install integration"}, status=200) msg = MessageBuilder( subject="Your team member requested the %s integration on Sentry" % provider_name, template="sentry/emails/requests/organization-integration.txt", html_template= "sentry/emails/requests/organization-integration.html", type="organization.integration.request", context={ "integration_link": get_url(organization, provider_type, provider_slug), "integration_name": provider_name, "message": message_option, "organization_name": organization.name, "requester_name": requester.name or requester.username, "requester_link": absolute_uri( f"/settings/{organization.slug}/members/{requester.id}/"), "settings_link": absolute_uri( reverse("sentry-organization-settings", args=[organization.slug])), }, ) msg.send([user.email for user in owners_list]) return Response(status=201)
def send_notification(self): from sentry.utils.email import MessageBuilder if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_list = set(m.user for m in AccessGroup.objects.filter( projects=self.project, members__is_active=True, ).exclude(members__id=self.user_id, )) if self.project.team: # fetch team members user_list |= set( m.user for m in self.project.team.member_set.filter( user__is_active=True, ).exclude(user__id=self.user_id, )) if not user_list: return disabled = set( UserOption.objects.filter( user__in=user_list, key='subscribe_comments', value='0', ).values_list('user', flat=True)) send_to = [ u.email for u in user_list if u.email and u.id not in disabled ] if not send_to: return author = self.user.first_name or self.user.username subject = '%s: %s' % (author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', ) try: msg.send(to=send_to) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_stripped_newline(self): msg = MessageBuilder(subject="Foo\r\nBar", body="hello world", html_body="<b>hello world</b") msg.send(["*****@*****.**"]) assert len(mail.outbox) == 1 assert mail.outbox[0].subject == "Foo"
def test_reply_reference(self, make_msgid): make_msgid.return_value = 'abc123' msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.activity, reply_reference=self.group, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Re: Test' assert out.extra_headers['Message-Id'] == 'abc123' assert 'In-Reply-To' not in out.extra_headers assert 'References' not in out.extra_headers assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', ) # Our new EmailThread row was added assert GroupEmailThread.objects.count() == 1 thread = GroupEmailThread.objects.all()[0] assert thread.msgid == 'abc123' assert thread.email == '*****@*****.**' assert thread.group == self.group # new msgid for the next message make_msgid.return_value = '321cba' msg.send(['*****@*****.**']) assert len(mail.outbox) == 2 out = mail.outbox[1] assert out.to == ['*****@*****.**'] assert out.subject == 'Re: Test' assert out.extra_headers['Message-Id'] == '321cba' assert out.extra_headers['In-Reply-To'] == 'abc123' assert out.extra_headers['References'] == 'abc123' assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', ) # Our new GroupEmailThread row was added assert GroupEmailThread.objects.count( ) == 1, 'Should not have added a new row' assert GroupEmailThread.objects.all( )[0].msgid == 'abc123', 'msgid should not have changed'
def test_reply_reference(self, make_msgid): make_msgid.return_value = "abc123" msg = MessageBuilder( subject="Test", body="hello world", html_body="<b>hello world</b>", reference=self.activity, reply_reference=self.group, ) msg.send(["*****@*****.**"]) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ["*****@*****.**"] assert out.subject == "Re: Test" assert out.extra_headers["Message-Id"] == "abc123" assert "In-Reply-To" not in out.extra_headers assert "References" not in out.extra_headers assert out.body == "hello world" assert len(out.alternatives) == 1 assert out.alternatives[0] == ( "<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>", "text/html", ) # Our new EmailThread row was added assert GroupEmailThread.objects.count() == 1 thread = GroupEmailThread.objects.all()[0] assert thread.msgid == "abc123" assert thread.email == "*****@*****.**" assert thread.group == self.group # new msgid for the next message make_msgid.return_value = "321cba" msg.send(["*****@*****.**"]) assert len(mail.outbox) == 2 out = mail.outbox[1] assert out.to == ["*****@*****.**"] assert out.subject == "Re: Test" assert out.extra_headers["Message-Id"] == "321cba" assert out.extra_headers["In-Reply-To"] == "abc123" assert out.extra_headers["References"] == "abc123" assert out.body == "hello world" assert len(out.alternatives) == 1 assert out.alternatives[0] == ( "<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>", "text/html", ) # Our new GroupEmailThread row was added assert GroupEmailThread.objects.count( ) == 1, "Should not have added a new row" assert GroupEmailThread.objects.all( )[0].msgid == "abc123", "msgid should not have changed"
def test_bcc_on_send(self): msg = MessageBuilder(subject="Test", body="hello world") msg.send(["*****@*****.**"], bcc=["*****@*****.**"]) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ["*****@*****.**"] assert out.bcc == ["*****@*****.**"]
def test_reply_reference(self, make_msgid): make_msgid.return_value = 'abc123' msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.activity, reply_reference=self.group, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Re: Test' assert out.extra_headers['Message-Id'] == 'abc123' assert 'In-Reply-To' not in out.extra_headers assert 'References' not in out.extra_headers assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', ) # Our new EmailThread row was added assert GroupEmailThread.objects.count() == 1 thread = GroupEmailThread.objects.all()[0] assert thread.msgid == 'abc123' assert thread.email == '*****@*****.**' assert thread.group == self.group # new msgid for the next message make_msgid.return_value = '321cba' msg.send(['*****@*****.**']) assert len(mail.outbox) == 2 out = mail.outbox[1] assert out.to == ['*****@*****.**'] assert out.subject == 'Re: Test' assert out.extra_headers['Message-Id'] == '321cba' assert out.extra_headers['In-Reply-To'] == 'abc123' assert out.extra_headers['References'] == 'abc123' assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', ) # Our new GroupEmailThread row was added assert GroupEmailThread.objects.count() == 1, 'Should not have added a new row' assert GroupEmailThread.objects.all()[0].msgid == 'abc123', 'msgid should not have changed'
def test_stripped_newline(self): msg = MessageBuilder( subject='Foo\r\nBar', body='hello world', html_body='<b>hello world</b', ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 assert mail.outbox[0].subject == 'Foo'
def test_stripped_newline(self): msg = MessageBuilder( subject='Foo\r\nBar', body='hello world', html_body='<b>hello world</b', ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 assert mail.outbox[0].subject == 'Foo'
def test_bcc_on_send(self): msg = MessageBuilder( subject='Test', body='hello world', ) msg.send(['*****@*****.**'], bcc=['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.bcc == ['*****@*****.**']
def test_bcc_on_send(self): msg = MessageBuilder( subject='Test', body='hello world', ) msg.send(['*****@*****.**'], bcc=['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.bcc == ['*****@*****.**']
def _send_mail(self, subject, body, html_body=None, project=None, headers=None, fail_silently=False): send_to = self.get_send_to(project) if not send_to: return subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), body=body, html_body=html_body, headers=headers, ) msg.send(send_to, fail_silently=fail_silently)
def _send_mail(self, subject, template=None, html_template=None, body=None, project=None, group=None, headers=None, context=None, fail_silently=False): send_to = self.get_send_to(project) if not send_to: return subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix try: subject_prefix = subject_prefix.encode("utf-8") subject = subject.encode("utf-8") except UnicodeDecodeError: subject_prefix = unicode(subject_prefix, "utf-8") subject = unicode(subject, "utf-8") msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, reference=group, ) msg.add_users(send_to, project=project) return msg.send(fail_silently=fail_silently)
def _send_mail( self, subject, template=None, html_template=None, body=None, project=None, headers=None, context=None, fail_silently=False, ): subject_prefix = self.get_option("subject_prefix", project) or self.subject_prefix msg = MessageBuilder( subject="%s%s" % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, ) send_to = self._send_to return msg.send(to=send_to, fail_silently=fail_silently)
def _send_mail(self, subject, template=None, html_template=None, body=None, project=None, headers=None, context=None, fail_silently=False): subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, ) send_to = self._send_to return msg.send(to=send_to, fail_silently=fail_silently)
def _send_mail(self, subject, template=None, html_template=None, body=None, project=None, group=None, headers=None, context=None): send_to = self.get_send_to(project) if not send_to: return subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, reference=group, ) msg.add_users(send_to, project=project) return msg.send()
def after(self, event, state): mail_plugin = plugins.get('mail') if not mail_plugin.is_enabled(event.project): return username = self.get_option('username') try: user = User.objects.get(username=username) except: return project = event.project group = event.group subject_prefix = mail_plugin.get_option('subject_prefix', project) or settings.EMAIL_SUBJECT_PREFIX interface_list = [] for interface in event.interfaces.itervalues(): body = interface.to_email_html(event) if not body: continue interface_list.append((interface.get_title(), mark_safe(body))) subject = group.get_email_subject() link = group.get_absolute_url() template = 'sentry/emails/error.txt' html_template = 'sentry/emails/error.html' context = { 'group': group, 'event': event, 'tags': event.get_tags(), 'link': link, 'interfaces': interface_list, 'rule': None, 'rule_link': None, } headers = { 'X-Sentry-Logger': group.logger, 'X-Sentry-Logger-Level': group.get_level_display(), 'X-Sentry-Project': project.name, 'X-Sentry-Reply-To': group_id_to_email(group.id), } msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, reference=group, ) msg.add_users([user.id], project=project) return msg.send()
def send_notification(self): from sentry.utils.email import MessageBuilder if self.type != Activity.NOTE or not self.group: return user_list = list(User.objects.filter( groupseen__group=self.group, ).exclude(user=self.user)) disabled = set(UserOption.objects.filter( user__in=user_list, key='subscribe_comments', value='0')) send_to = [ u.email for u in user_list if u.id not in disabled and u.email ] author = self.user.first_name or self.user.username subject = '%s: %s' % ( author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', ) try: msg.send(to=send_to) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_raw_content(self): msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', headers={'X-Test': 'foo'}, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Test' assert out.extra_headers['X-Test'] == 'foo' assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', )
def send_invite_email(self): from sentry.utils.email import MessageBuilder context = { "email": self.email, "team": self.team, "url": absolute_uri(reverse("sentry-accept-invite", kwargs={"member_id": self.id, "token": self.token})), } msg = MessageBuilder( subject="Invite to join team: %s" % (self.team.name,), template="sentry/emails/member_invite.txt", context=context, ) try: msg.send([self.email]) except Exception, e: logger = logging.getLogger("sentry.mail.errors") logger.exception(e)
def test_explicit_reply_to(self): msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', headers={'X-Sentry-Reply-To': '*****@*****.**'}, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Test' assert out.extra_headers['Reply-To'] == '*****@*****.**' assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', )
def send_notification(self): from sentry.utils.email import MessageBuilder if self.type != Activity.NOTE or not self.group: return user_list = list( User.objects.filter( groupseen__group=self.group, ).exclude(id=self.user.id)) disabled = set( UserOption.objects.filter(user__in=user_list, key='subscribe_comments', value='0')) send_to = [ u.email for u in user_list if u.id not in disabled and u.email ] author = self.user.first_name or self.user.username subject = '%s: %s' % (author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', ) try: msg.send(to=send_to) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_message_id(self): msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.activity, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Test' assert out.extra_headers['Message-Id'] == '<activity/%s@localhost>' % self.activity.pk assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<html><body><b>hello world</b></body></html>', 'text/html', )
def test_explicit_reply_to(self): msg = MessageBuilder( subject="Test", body="hello world", html_body="<b>hello world</b>", headers={"X-Sentry-Reply-To": "*****@*****.**"}, ) msg.send(["*****@*****.**"]) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ["*****@*****.**"] assert out.subject == "Test" assert out.extra_headers["Reply-To"] == "*****@*****.**" assert out.body == "hello world" assert len(out.alternatives) == 1 assert out.alternatives[0] == ( "<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>", "text/html", )
def test_raw_content(self): msg = MessageBuilder( subject="Test", body="hello world", html_body="<b>hello world</b>", headers={"X-Test": "foo"}, ) msg.send(["*****@*****.**"]) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ["*****@*****.**"] assert out.subject == "Test" assert out.extra_headers["X-Test"] == "foo" assert out.body == "hello world" assert len(out.alternatives) == 1 assert out.alternatives[0] == ( "<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>", "text/html", )
def test_inline_css(self): msg = MessageBuilder( subject="Test", body="hello world", html_body="<head><style type='text/css'>h1 { color: red; }</style></head><h1>foobar</h1><h2><b>hello world</b></h2>", headers={"X-Test": "foo"}, ) msg.send(["*****@*****.**"]) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ["*****@*****.**"] assert out.subject == "Test" assert out.extra_headers["X-Test"] == "foo" assert out.body == "hello world" assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><head></head><body><h1 style="color: red">foobar</h1><h2><b>hello world</b></h2></body></html>', "text/html", )
def test_fake_dont_send(self): project = self.project user_a = User.objects.create(email=create_fake_email("foo", "fake")) user_b = User.objects.create(email=create_fake_email("bar", "fake")) user_c = User.objects.create(email=create_fake_email("baz", "fake")) UserOption.objects.create( user=user_c, project=project, key="mail:email", value=create_fake_email("bazzer", "fake"), ) msg = MessageBuilder(subject="Test", body="hello world", html_body="<!DOCTYPE html>\n<b>hello world</b>") msg.add_users([user_a.id, user_b.id, user_c.id], project=project) msg.send() assert len(mail.outbox) == 0
def test_message_id(self, make_msgid): make_msgid.return_value = 'abc123' msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.activity, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Test' assert out.extra_headers['Message-Id'] == 'abc123' assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<!DOCTYPE html>\n<html><body><b>hello world</b></body></html>', 'text/html', )
def send_recover_mail(self): from sentry.utils.email import MessageBuilder context = { 'user': self.user, 'domain': urlparse.urlparse(settings.SENTRY_URL_PREFIX).hostname, 'url': absolute_uri(reverse( 'sentry-account-recover-confirm', args=[self.user.id, self.hash] )), } msg = MessageBuilder( subject='%sPassword Recovery' % (settings.EMAIL_SUBJECT_PREFIX,), template='sentry/emails/recover_account.txt', context=context, ) try: msg.send([self.user.email]) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_sso_link_email(self): from sentry.utils.email import MessageBuilder context = { 'email': self.email, 'organization_name': self.organization.name, 'url': absolute_uri(reverse('sentry-auth-link-identity', kwargs={ 'organization_slug': self.organization.slug, })), } msg = MessageBuilder( subject='Action Required for %s' % (self.organization.name,), template='sentry/emails/auth-link-identity.txt', html_template='sentry/emails/auth-link-identity.html', context=context, ) try: msg.send([self.get_email()]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_sso_link_email(self): from sentry.utils.email import MessageBuilder context = { "email": self.email, "organization_name": self.organization.name, "url": absolute_uri( reverse("sentry-auth-link-identity", kwargs={"organization_slug": self.organization.slug}) ), } msg = MessageBuilder( subject="Action Required for %s" % (self.organization.name,), template="sentry/emails/auth-link-identity.txt", html_template="sentry/emails/auth-link-identity.html", context=context, ) try: msg.send([self.get_email()]) except Exception as e: logger = logging.getLogger("sentry.mail.errors") logger.exception(e)
def send_invite_email(self): from sentry.utils.email import MessageBuilder context = { 'email': self.email, 'team': self.team, 'url': absolute_uri(reverse('sentry-accept-invite', kwargs={ 'member_id': self.id, 'token': self.token, })), } msg = MessageBuilder( subject='Invite to join team: %s' % (self.team.name,), template='sentry/emails/member_invite.txt', context=context, ) try: msg.send([self.email]) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_invite_email(self): from sentry.utils.email import MessageBuilder context = { 'email': self.email, 'organization': self.organization, 'url': absolute_uri(reverse('sentry-accept-invite', kwargs={ 'member_id': self.id, 'token': self.token, })), } msg = MessageBuilder( subject='Join %s in using Sentry' % self.organization.name, template='sentry/emails/member-invite.txt', html_template='sentry/emails/member-invite.html', context=context, ) try: msg.send([self.get_email()]) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def test_in_reply_to(self): msg = MessageBuilder( subject='Test', body='hello world', html_body='<b>hello world</b>', reference=self.activity, reply_reference=self.group, ) msg.send(['*****@*****.**']) assert len(mail.outbox) == 1 out = mail.outbox[0] assert out.to == ['*****@*****.**'] assert out.subject == 'Re: Test' assert out.extra_headers['Message-Id'] == '<activity/%s@localhost>' % self.activity.pk assert out.extra_headers['In-Reply-To'] == '<group/%s@localhost>' % self.group.pk assert out.extra_headers['References'] == '<group/%s@localhost>' % self.group.pk assert out.body == 'hello world' assert len(out.alternatives) == 1 assert out.alternatives[0] == ( '<b>hello world</b>', 'text/html', )
def _send_mail(self, subject, template=None, html_template=None, body=None, project=None, headers=None, context=None, fail_silently=False): send_to = self.get_send_to(project) if not send_to: return subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, ) msg.add_users(send_to, project=project) return msg.send(fail_silently=fail_silently)
def _send_mail(self, subject, template=None, html_template=None, body=None, project=None, group=None, headers=None, context=None): send_to = self.get_send_to(project) if not send_to: return subject_prefix = self.get_option('subject_prefix', project) or self.subject_prefix subject_prefix = force_text(subject_prefix) subject = force_text(subject) msg = MessageBuilder( subject='%s%s' % (subject_prefix, subject), template=template, html_template=html_template, body=body, headers=headers, context=context, reference=group, ) msg.add_users(send_to, project=project) return msg.send()
def send_notification(self): from sentry.models import User, UserOption, ProjectOption from sentry.utils.email import MessageBuilder, group_id_to_email if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_id_list = set( User.objects.filter( accessgroup__projects=self.project, is_active=True ).exclude( id=self.user_id, ).values_list('id', flat=True) ) if self.project.team: # fetch team members user_id_list |= set( u_id for u_id in self.project.team.member_set.filter( user__is_active=True, ).exclude( user__id=self.user_id, ).values_list('user', flat=True) ) if not user_id_list: return disabled = set(UserOption.objects.filter( user__in=user_id_list, key='subscribe_notes', value=u'0', ).values_list('user', flat=True)) send_to = filter(lambda u_id: u_id not in disabled, user_id_list) if not send_to: return author = self.user.first_name or self.user.username subject_prefix = ProjectOption.objects.get_value( self.project, 'subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' subject = '%s%s' % (subject_prefix, self.event.get_email_subject()) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.pk), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', headers=headers, reference=self, reply_reference=self.group, ) msg.add_users(send_to, project=self.project) try: msg.send() except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def notify_about_activity(self, activity): if activity.type not in (Activity.NOTE, Activity.ASSIGNED, Activity.RELEASE): return candidate_ids = set(self.get_send_to(activity.project)) # Never send a notification to the user that performed the action. candidate_ids.discard(activity.user_id) if activity.type == Activity.ASSIGNED: # Only notify the assignee, and only if they are in the candidate set. recipient_ids = candidate_ids & set((activity.data['assignee'],)) elif activity.type == Activity.NOTE: recipient_ids = candidate_ids - set( UserOption.objects.filter( user__in=candidate_ids, key='subscribe_notes', value=u'0', ).values_list('user', flat=True) ) else: recipient_ids = candidate_ids if not recipient_ids: return project = activity.project org = project.organization group = activity.group headers = {} context = { 'data': activity.data, 'author': activity.user, 'project': project, 'project_link': absolute_uri(reverse('sentry-stream', kwargs={ 'organization_slug': org.slug, 'project_id': project.slug, })), } if group: group_link = absolute_uri('/{}/{}/issues/{}/'.format( org.slug, project.slug, group.id )) activity_link = '{}activity/'.format(group_link) headers.update({ 'X-Sentry-Reply-To': group_id_to_email(group.id), }) context.update({ 'group': group, 'link': group_link, 'activity_link': activity_link, }) # TODO(dcramer): abstract each activity email into its own helper class if activity.type == Activity.RELEASE: context.update({ 'release': Release.objects.get( version=activity.data['version'], project=project, ), 'release_link': absolute_uri('/{}/{}/releases/{}/'.format( org.slug, project.slug, activity.data['version'], )), }) template_name = activity.get_type_display() # TODO: Everything below should instead use `_send_mail` for consistency. subject_prefix = project.get_option('subject_prefix', settings.EMAIL_SUBJECT_PREFIX) if subject_prefix: subject_prefix = subject_prefix.rstrip() + ' ' if group: subject = '%s%s' % (subject_prefix, group.get_email_subject()) elif activity.type == Activity.RELEASE: subject = '%sRelease %s' % (subject_prefix, activity.data['version']) else: raise NotImplementedError msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/activity/{}.txt'.format(template_name), html_template='sentry/emails/activity/{}.html'.format(template_name), headers=headers, reference=activity, reply_reference=group, ) msg.add_users(recipient_ids, project=project) msg.send()
def send_notification(self): from sentry.models import User, UserOption from sentry.utils.email import MessageBuilder, group_id_to_email if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_id_list = set( User.objects.filter( accessgroup__projects=self.project, is_active=True ).exclude( id=self.user_id, ).values_list('id', flat=True) ) if self.project.team: # fetch team members user_id_list |= set( u_id for u_id in self.project.team.member_set.filter( user__is_active=True, ).exclude( user__id=self.user_id, ).values_list('user', flat=True) ) if not user_id_list: return disabled = set(UserOption.objects.filter( user__in=user_id_list, key='subscribe_comments', value='0', ).values_list('user', flat=True)) send_to = [ u_id for u_id in user_id_list if u_id not in disabled ] if not send_to: return author = self.user.first_name or self.user.username subject = '[%s] %s: %s' % ( self.project.name, author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } headers = { 'X-Sentry-Reply-To': group_id_to_email(self.group.pk), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', headers=headers, ) msg.add_users(send_to, project=self.project) try: msg.send() except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)
def send_notification(self): from sentry.utils.email import MessageBuilder if self.type != Activity.NOTE or not self.group: return # TODO(dcramer): some of this logic is duplicated in NotificationPlugin # fetch access group members user_list = set( m.user for m in AccessGroup.objects.filter( projects=self.project, members__is_active=True, ).exclude( members__id=self.user_id, ) ) if self.project.team: # fetch team members user_list |= set( m.user for m in self.project.team.member_set.filter( user__is_active=True, ).exclude( user__id=self.user_id, ) ) if not user_list: return disabled = set(UserOption.objects.filter( user__in=user_list, key='subscribe_comments', value='0', ).values_list('user', flat=True)) send_to = [ u.email for u in user_list if u.email and u.id not in disabled ] if not send_to: return author = self.user.first_name or self.user.username subject = '%s: %s' % ( author, self.data['text'].splitlines()[0][:64]) context = { 'text': self.data['text'], 'author': author, 'group': self.group, 'link': self.group.get_absolute_url(), } msg = MessageBuilder( subject=subject, context=context, template='sentry/emails/new_note.txt', html_template='sentry/emails/new_note.html', ) try: msg.send(to=send_to) except Exception, e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e)