|
| 1 | +# Suppression List Removal Feature - Implementation Summary |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +Users whose email addresses end up on the AWS SES suppression list cannot receive emails from Notify, including password reset emails. This happens due to temporary issues like: |
| 6 | +- Email server downtime |
| 7 | +- Incorrect email server response codes |
| 8 | +- Overactive email filters |
| 9 | + |
| 10 | +Without manual support intervention, these users cannot regain access to Notify. |
| 11 | + |
| 12 | +## Solution |
| 13 | + |
| 14 | +Implemented a self-service feature that allows service administrators to remove email addresses from the suppression list through the Notify interface. |
| 15 | + |
| 16 | +## Implementation Details |
| 17 | + |
| 18 | +### Backend API (notification-api) - COMPLETED ✅ |
| 19 | + |
| 20 | +#### Files Modified |
| 21 | +1. `app/dao/notifications_dao.py` (+27 lines) |
| 22 | +2. `app/clients/email/aws_ses.py` (+30 lines) |
| 23 | +3. `app/service/rest.py` (+74 lines) |
| 24 | +4. `app/schemas.py` (+19 lines) |
| 25 | +5. `app/clients/freshdesk.py` (+3 lines) |
| 26 | + |
| 27 | +#### Files Created |
| 28 | +6. `tests/app/service/test_suppression_list.py` (174 lines) |
| 29 | +7. `tests/app/dao/notification_dao/test_notification_dao.py` (+84 lines) |
| 30 | +8. `tests/app/clients/test_aws_ses.py` (+72 lines) |
| 31 | +9. `ADMIN_CHANGES_REQUIRED.md` (305 lines) |
| 32 | + |
| 33 | +**Total: 788 lines added** |
| 34 | + |
| 35 | +### Key Components |
| 36 | + |
| 37 | +#### 1. Database Access Layer (DAO) |
| 38 | +- **Function**: `dao_check_service_has_sent_to_email(service_id, email_address)` |
| 39 | +- **Purpose**: Verify that a service has actually sent to an email address before allowing removal |
| 40 | +- **Features**: |
| 41 | + - Case-insensitive email matching |
| 42 | + - Excludes test key notifications |
| 43 | + - Uses normalized email addresses from notifications table |
| 44 | + |
| 45 | +#### 2. AWS SES Client Enhancement |
| 46 | +- **Function**: `remove_email_from_suppression_list(email_address)` |
| 47 | +- **Technology**: AWS SES v2 API (`delete_suppressed_destination`) |
| 48 | +- **Features**: |
| 49 | + - Handles "NotFound" gracefully (email not in suppression list) |
| 50 | + - Comprehensive error handling and logging |
| 51 | + - Statsd metrics for monitoring: |
| 52 | + - `clients.ses.suppression-removal.success` |
| 53 | + - `clients.ses.suppression-removal.not-found` |
| 54 | + - `clients.ses.suppression-removal.error` |
| 55 | + |
| 56 | +#### 3. REST API Endpoint |
| 57 | +- **Route**: `POST /service/<service_id>/remove-from-suppression-list` |
| 58 | +- **Authentication**: Required (service authorization) |
| 59 | +- **Request Body**: `{ "email_address": "user@example.com" }` |
| 60 | +- **Validation Steps**: |
| 61 | + 1. Service exists |
| 62 | + 2. Email address is valid format |
| 63 | + 3. Service has sent to this email address |
| 64 | +- **Actions**: |
| 65 | + 1. Remove email from AWS SES suppression list |
| 66 | + 2. Create Freshdesk ticket for audit trail (non-blocking) |
| 67 | +- **Response Codes**: |
| 68 | + - `200`: Success |
| 69 | + - `400`: Invalid email format |
| 70 | + - `404`: Service not found or email never sent to |
| 71 | + - `500`: SES removal failed |
| 72 | + |
| 73 | +#### 4. Schema Validation |
| 74 | +- **Schema**: `SuppressionRemovalSchema` |
| 75 | +- **Validates**: Email address format using `validate_email_address()` |
| 76 | + |
| 77 | +#### 5. Freshdesk Integration |
| 78 | +- **Automatic Ticket Creation**: Every removal generates a support ticket |
| 79 | +- **Ticket Content**: |
| 80 | + - Service name and ID |
| 81 | + - Email address removed |
| 82 | + - Timestamp |
| 83 | +- **Non-Blocking**: Freshdesk failures don't prevent removal |
| 84 | + |
| 85 | +### Test Coverage |
| 86 | + |
| 87 | +#### Service REST Tests (8 test cases) |
| 88 | +- ✅ Successful removal |
| 89 | +- ✅ Email not sent by service (404) |
| 90 | +- ✅ Invalid email format (400) |
| 91 | +- ✅ Missing email address (400) |
| 92 | +- ✅ SES client error handling (500) |
| 93 | +- ✅ Freshdesk failure handling (non-blocking) |
| 94 | +- ✅ Service not found (404) |
| 95 | +- ✅ Case-insensitive email matching |
| 96 | + |
| 97 | +#### DAO Tests (8 test cases) |
| 98 | +- ✅ Returns true when service has sent to email |
| 99 | +- ✅ Case-insensitive matching |
| 100 | +- ✅ Returns false when service hasn't sent to email |
| 101 | +- ✅ Returns false for different service |
| 102 | +- ✅ Ignores test key notifications |
| 103 | +- ✅ Multiple notifications to same email |
| 104 | +- ✅ SMS notifications don't affect email checking |
| 105 | +- ✅ Email normalization |
| 106 | + |
| 107 | +#### AWS SES Client Tests (4 test cases) |
| 108 | +- ✅ Successful removal |
| 109 | +- ✅ Email not in suppression list (treated as success) |
| 110 | +- ✅ SES error handling |
| 111 | +- ✅ Unexpected error handling |
| 112 | + |
| 113 | +### Security Features |
| 114 | + |
| 115 | +1. **Service Authorization**: Only authorized service members can remove emails |
| 116 | +2. **Verification**: Can only remove emails the service has actually sent to |
| 117 | +3. **Audit Trail**: All removals logged and tracked via Freshdesk |
| 118 | +4. **Non-Test Only**: Test key notifications are excluded from verification |
| 119 | + |
| 120 | +### Monitoring & Observability |
| 121 | + |
| 122 | +1. **Logging**: |
| 123 | + - Successful removals |
| 124 | + - Failed removals with error details |
| 125 | + - Freshdesk ticket creation status |
| 126 | + |
| 127 | +2. **Metrics** (Statsd): |
| 128 | + - Success rate |
| 129 | + - Not found rate |
| 130 | + - Error rate |
| 131 | + |
| 132 | +3. **Audit Trail**: |
| 133 | + - Freshdesk tickets for all removals |
| 134 | + - Includes service, email, and timestamp |
| 135 | + |
| 136 | +## Frontend UI (notification-admin) - PENDING |
| 137 | + |
| 138 | +The `ADMIN_CHANGES_REQUIRED.md` document provides comprehensive instructions for implementing the UI, including: |
| 139 | + |
| 140 | +1. Route handlers and view functions |
| 141 | +2. Form definitions |
| 142 | +3. API client methods |
| 143 | +4. HTML templates |
| 144 | +5. Service settings integration |
| 145 | +6. Test cases |
| 146 | +7. Integration testing steps |
| 147 | + |
| 148 | +**A separate PR is required in the notification-admin repository.** |
| 149 | + |
| 150 | +## Testing in Production |
| 151 | + |
| 152 | +### Prerequisites |
| 153 | +1. Both notification-api and notification-admin deployed |
| 154 | +2. AWS SES credentials configured |
| 155 | +3. Freshdesk integration enabled |
| 156 | + |
| 157 | +### Test Scenario |
| 158 | +1. Create a test email that will bounce |
| 159 | +2. Send an email to it from a test service |
| 160 | +3. Verify email is added to suppression list |
| 161 | +4. Log in to notification-admin as service admin |
| 162 | +5. Navigate to service settings → Manage suppression list |
| 163 | +6. Enter the email address |
| 164 | +7. Submit the form |
| 165 | +8. Verify success message |
| 166 | +9. Check Freshdesk for ticket |
| 167 | +10. Verify email is removed from suppression list |
| 168 | +11. Attempt to send email again (should succeed) |
| 169 | + |
| 170 | +## API Usage Example |
| 171 | + |
| 172 | +```bash |
| 173 | +# Remove email from suppression list |
| 174 | +curl -X POST \ |
| 175 | + https://api.notification.canada.ca/service/{service_id}/remove-from-suppression-list \ |
| 176 | + -H 'Authorization: Bearer {token}' \ |
| 177 | + -H 'Content-Type: application/json' \ |
| 178 | + -d '{ |
| 179 | + "email_address": "user@example.com" |
| 180 | + }' |
| 181 | + |
| 182 | +# Success Response (200) |
| 183 | +{ |
| 184 | + "message": "Successfully removed user@example.com from suppression list" |
| 185 | +} |
| 186 | + |
| 187 | +# Error Response - Not sent by service (404) |
| 188 | +{ |
| 189 | + "message": "Service Example Service has not sent any notifications to user@example.com" |
| 190 | +} |
| 191 | + |
| 192 | +# Error Response - Invalid email (400) |
| 193 | +{ |
| 194 | + "message": { |
| 195 | + "email_address": ["Not a valid email address"] |
| 196 | + } |
| 197 | +} |
| 198 | +``` |
| 199 | + |
| 200 | +## Benefits |
| 201 | + |
| 202 | +1. **Self-Service**: Users can resolve suppression issues without support tickets |
| 203 | +2. **Faster Resolution**: Immediate removal instead of waiting for support |
| 204 | +3. **Reduced Support Load**: Fewer manual interventions needed |
| 205 | +4. **Audit Trail**: All removals tracked automatically |
| 206 | +5. **Safe**: Only allows removal of emails service has sent to |
| 207 | +6. **Monitored**: Comprehensive logging and metrics |
| 208 | + |
| 209 | +## Limitations & Considerations |
| 210 | + |
| 211 | +1. **Account-Level Only**: Only removes from account suppression list (not global) |
| 212 | +2. **Email Only**: SMS opt-out removal not included (monthly limit per AWS) |
| 213 | +3. **Service Scope**: Can only remove emails the service has sent to |
| 214 | +4. **No Bulk Operations**: One email at a time |
| 215 | +5. **Rate Limiting**: Should be considered to prevent abuse |
| 216 | + |
| 217 | +## Future Enhancements |
| 218 | + |
| 219 | +1. Bulk removal capability |
| 220 | +2. Suppression list viewing (current emails on list) |
| 221 | +3. Automatic removal on password reset attempts |
| 222 | +4. Email notifications when address is suppressed |
| 223 | +5. Dashboard for suppression metrics |
| 224 | + |
| 225 | +## Rollout Plan |
| 226 | + |
| 227 | +### Phase 1: API Deployment (Current) |
| 228 | +- Deploy notification-api changes |
| 229 | +- Monitor metrics and logs |
| 230 | +- Validate with API tests |
| 231 | + |
| 232 | +### Phase 2: UI Development (Next) |
| 233 | +- Implement notification-admin changes per documentation |
| 234 | +- Test integration between admin and API |
| 235 | +- User acceptance testing |
| 236 | + |
| 237 | +### Phase 3: Production Rollout |
| 238 | +- Deploy to staging |
| 239 | +- Test with real suppression list entries |
| 240 | +- Deploy to production |
| 241 | +- Monitor closely for first week |
| 242 | +- Document any issues |
| 243 | + |
| 244 | +## Support & Documentation |
| 245 | + |
| 246 | +- **API Documentation**: Updated API docs with new endpoint |
| 247 | +- **Admin Guide**: `ADMIN_CHANGES_REQUIRED.md` for UI implementation |
| 248 | +- **Operations Guide**: Monitoring and troubleshooting procedures |
| 249 | +- **User Guide**: To be created with screenshots after UI implementation |
| 250 | + |
| 251 | +## Conclusion |
| 252 | + |
| 253 | +The backend implementation is complete and tested. The feature provides a safe, auditable way for service administrators to remove email addresses from the suppression list, addressing the issue of users being unable to access Notify due to temporary email delivery issues. |
| 254 | + |
| 255 | +The next step is implementing the UI in notification-admin as documented in `ADMIN_CHANGES_REQUIRED.md`. |
0 commit comments