.agents/skills/notification-platform/references/targets-and-sending.md
Used when no integration is needed. The resource_id is the recipient's email address.
from sentry.notifications.platform.target import GenericNotificationTarget
from sentry.notifications.platform.types import (
NotificationProviderKey,
NotificationTargetResourceType,
)
target = GenericNotificationTarget(
provider_key=NotificationProviderKey.EMAIL,
resource_type=NotificationTargetResourceType.EMAIL,
resource_id="[email protected]",
)
Real example (from data export sending):
target = GenericNotificationTarget(
provider_key=NotificationProviderKey.EMAIL,
resource_type=NotificationTargetResourceType.EMAIL,
resource_id=user.email,
)
Used when sending through an integration. Requires integration_id and organization_id in addition to the base target fields.
from sentry.notifications.platform.target import IntegrationNotificationTarget
target = IntegrationNotificationTarget(
provider_key=NotificationProviderKey.SLACK,
resource_type=NotificationTargetResourceType.CHANNEL,
resource_id="C01ABC23DEF", # Slack channel ID
integration_id=integration.id,
organization_id=organization.id,
)
For direct messages, use NotificationTargetResourceType.DIRECT_MESSAGE and the user's provider-specific ID as resource_id.
| Provider | Supported resource types |
|---|---|
EMAIL | |
| Slack | CHANNEL, DIRECT_MESSAGE |
| Discord | CHANNEL, DIRECT_MESSAGE |
| MS Teams | CHANNEL, DIRECT_MESSAGE |
| Method | Behavior | Use when |
|---|---|---|
notify_async(targets=[...]) | Sends via Celery task. Fire-and-forget. | Default choice. Most notifications. |
notify_sync(targets=[...]) | Sends synchronously. Returns dict[ProviderKey, list[str]] of errors. | You need to report errors back to the caller. |
notify_target(target=...) | Sends one target synchronously. Ignores notification settings. | Low-level. Called internally by the other methods. |
All three methods require the service to be initialized with data:
service = NotificationService(data=my_data)
Instead of constructing targets manually, you can implement NotificationStrategy:
from sentry.notifications.platform.types import NotificationStrategy, NotificationTarget
class MyNotificationStrategy(NotificationStrategy):
def __init__(self, organization, project):
self.organization = organization
self.project = project
def get_targets(self) -> list[NotificationTarget]:
# Query for relevant users/channels and build targets
return [
GenericNotificationTarget(
provider_key=NotificationProviderKey.EMAIL,
resource_type=NotificationTargetResourceType.EMAIL,
resource_id=member.email,
)
for member in self.get_relevant_members()
]
Then pass it to the service:
service.notify_async(strategy=MyNotificationStrategy(org, project))
You must provide either strategy or targets, not both. Strategies should be used whenever a notification is targeting multiple recipients, or must do complex lookup logic to construct a valid target.
NotificationService.has_access(organization, source) delegates to NotificationRolloutService, which:
| Priority | Feature flag | Option key |
|---|---|---|
| 1 (highest) | organizations:notification-platform.internal-testing | notifications.platform-rollout.internal-testing |
| 2 | organizations:notification-platform.is-sentry | notifications.platform-rollout.is-sentry |
| 3 | organizations:notification-platform.early-adopter | notifications.platform-rollout.early-adopter |
| 4 (lowest) | organizations:notification-platform.general-access | notifications.platform-rollout.general-access |
The four rollout options are already registered in src/sentry/options/defaults.py:
register(
"notifications.platform-rollout.internal-testing",
type=Dict,
default={},
flags=FLAG_AUTOMATOR_MODIFIABLE,
)
# ... same pattern for is-sentry, early-adopter, general-access
Rollout rates are configured in sentry-options-automator (separate repo). Each option is a dict mapping source string to float (0.0-1.0):
{
"data-export-success": 1.0, # 100% rollout
"my-new-source": 0.5, # 50% rollout
"experimental-feature": 0.01, # 1% rollout
}
from sentry.notifications.platform.service import NotificationService
data = MyNotificationData(...)
if NotificationService.has_access(organization, data.source):
service = NotificationService(data=data)
service.notify_async(targets=[target])
Always guard with has_access() before sending. This ensures rollout controls are respected.