Repository: getsentry/sentry

Issue:
Subject substitution issue on email alert for Performance issue 
The email I received 2 days ago showed the subject like:

![image](https://user-images.githubusercontent.com/1633368/229830519-ddfa03f7-9b87-4b71-b834-10088bdb11dc.png)

Docs indicate the environment should be replaced: 

> You’re able to change the subject line for alert emails within your Project’s Email Settings by going to Project Settings > Alerts > Settings. Email subjects can include variables such as $project, $title, and ${tag:key}, such as ${tag:environment} or ${tag:release}.

I confirmed `environment` exists [in the event:](https://testorg-az.sentry.io/issues/4056375822/?referrer=alert_email&alert_type=email&alert_timestamp=1680447601889&alert_rule_id=889972) 

![image](https://user-images.githubusercontent.com/1633368/229830411-1b7c6457-d2b8-4a70-86c2-a10eb1309e07.png)




Discussion:
@bruno-garcia have you noticed this for other issue alerts for errors or performance?
I was able to reproduce this. Happens for N+1 API Call, too, doesn't happen for error alerts. I think there's a bug with the email subject code, it's supposed to use a default template for Performance issues, but it doesn't. Also, not sure why it doesn't support the advanced template syntax like error issues 🤔 
Should this issue be routed to a specific team? Maybe performance? 🤔
Routing to @getsentry/performance for [triage](https://develop.sentry.dev/processing-tickets/#3-triage), due by **<time datetime=2023-04-06T21:00:00.000Z>Thursday, April 6th at 17:00</time> (yyz)**. ⏲️
@hubertdeng123 done. Already removed untriaged since @gggritso is on it

Resolving patch:
diff --git a/src/sentry/eventstore/models.py b/src/sentry/eventstore/models.py
--- a/src/sentry/eventstore/models.py
+++ b/src/sentry/eventstore/models.py
@@ -778,6 +778,9 @@ def __getitem__(self, name: str) -> str:
         if name.startswith("tag:"):
             name = name[4:]
             value = self.event.get_tag(self.tag_aliases.get(name, name))
+            if value is None:
+                value = self.event.get_tag(name)
+
             if value is None:
                 raise KeyError
             return str(value)
@@ -790,11 +793,13 @@ def __getitem__(self, name: str) -> str:
         elif name == "orgID":
             return cast(str, self.event.organization.slug)
         elif name == "title":
-            return (
-                self.event.occurrence.issue_title
-                if getattr(self.event, "occurrence", None)
-                else self.event.title
-            )
+            if getattr(self.event, "occurrence", None):
+                return self.event.occurrence.issue_title
+            elif self.event.group and self.event.group.issue_category == GroupCategory.PERFORMANCE:
+                return self.event.group.issue_type.description
+            else:
+                return self.event.title
+
         elif name == "issueType":
             return self.event.group.issue_type.description
         raise KeyError


Test patch:
diff --git a/tests/sentry/eventstore/test_models.py b/tests/sentry/eventstore/test_models.py
--- a/tests/sentry/eventstore/test_models.py
+++ b/tests/sentry/eventstore/test_models.py
@@ -12,6 +12,7 @@
 from sentry.models import Environment
 from sentry.snuba.dataset import Dataset
 from sentry.testutils import TestCase
+from sentry.testutils.cases import PerformanceIssueTestCase
 from sentry.testutils.helpers.datetime import before_now, iso_format
 from sentry.testutils.silo import region_silo_test
 from sentry.utils import snuba
@@ -19,7 +20,7 @@
 
 
 @region_silo_test
-class EventTest(TestCase):
+class EventTest(TestCase, PerformanceIssueTestCase):
     def test_pickling_compat(self):
         event = self.store_event(
             data={
@@ -105,6 +106,15 @@ def test_email_subject_with_template(self):
 
         assert event1.get_email_subject() == "BAR-1 - production@0 $ baz ${tag:invalid} $invalid"
 
+    def test_transaction_email_subject(self):
+        self.project.update_option(
+            "mail:subject_template",
+            "$shortID - ${tag:environment}@${tag:release} $title",
+        )
+
+        event = self.create_performance_issue()
+        assert event.get_email_subject() == "BAR-1 - production@0.1 N+1 Query"
+
     def test_as_dict_hides_client_ip(self):
         event = self.store_event(
             data={"sdk": {"name": "foo", "version": "1.0", "client_ip": "127.0.0.1"}},