-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MPP-3119: complaint notification disables mask #5045
MPP-3119: complaint notification disables mask #5045
Conversation
emails/views.py
Outdated
@@ -1634,6 +1645,22 @@ def _handle_complaint(message_json: AWS_SNSMessageJSON) -> HttpResponse: | |||
profile.auto_block_spam = True | |||
profile.save() | |||
|
|||
for destination_address in message_json.get("mail", {}).get("destination", []): | |||
try: | |||
address = _get_address(destination_address, False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: I changed the function call signature on this to accept a new bool
parameter to control if the function will/won't create the necessary DomainAddress
object.
There was enough logic in the _get_address
function that I didn't want to re-write it. I considered re-factoring into 2 separate _get_address
and _get_or_create_address
functions, but that would require changing all 17 calls _get_address
, which seemed like a more disruptive change.
7e17853
to
fc1c28d
Compare
edd78ff
to
324695d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank @groovecoder, looks good. The required changes are the same line:
- Move the code inside the loop, where
user
is set and so you can handle multiple recipients - Use
flag_is_active_in_task
to correctly handleeveryone=True
</h2> | ||
<p style=3D"line-height: 200%; margin-bottom: 30px; padding: = | ||
20px 60px 20px 60px"> | ||
Firefox Relay received a spam complaint for an email sent to = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 interesting, if the ftl_id ends with -html
, FTL does not add the unicode FSI and PDI codepoints. Maybe we need a { -brand-name-firefox-relay-html }
for these cases?
</p>=20 | ||
<a href=3D"http://127.0.0.1:8000/accounts/profile/#w41fwbt4q%= | ||
40test.com"> | ||
Visit your =E2=81=A8Firefox Relay=E2=81=A9 dashboard to r= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what the FSI and PDI codepoints look like in the HTML. The convert_fsi_to_span
filter changes these to <span dir="auto">...</span>
, but it can be a pain to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for getting this code worked on so quickly. I have some questions on why the create
parameter was added. I have some additional recommendations that will definitely scope creep:
- Add a field on the mask that the mask was blocked due to complaint. This can later on be used to filter mask for better UX and/or measuring how many masks were set to block in this way.
- Consider using a threshold to decide complaint resulting in blocking all emails. FxA tallies the number of complaint and bounces before they stop sending emails.
If an unknown email address is for a valid subdomain, and create is True, | ||
a new DomainAddress will be created. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(question, blocking) Can you explain why this was added? When will the create
be set to False
?
(suggestion, blocking) Also, if the create
parameter is only used to get/create DomainAddress
logic, I recommend making the create
parameter more descriptive like create_domainaddress
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This: #5045 (comment)
This other comment is where create
is set to False
, and the comment is right: it's "handling for getting a complaint on a DomainAddress that does not exist".
Let me consider how to address this.
emails/views.py
Outdated
def _disable_masks_for_complaint(message_json: dict) -> None: | ||
for destination_address in message_json.get("mail", {}).get("destination", []): | ||
try: | ||
address = _get_address(destination_address, False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(question, blocking) Why would the create
for DomainAddress
be set to False
? Is this handling for getting a complaint on a DomainAddress
that does not exist? If so, I think a different error should be raised from ObjectDoesNotExist
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's meant to handle if we ever receive a complaint for a DomainAddress that doesn't exist. E.g.:
- User creates a domain address
- User receives some email thru the address
- User deletes the domain address from Relay
- User sends a spam complaint about a past email sent thru the domain address
In this scenario, we don't want to re-create the old domain address.
It's raising ObjectDoesNotExist
just like _handle_received
and _reply_allowed
and the other code in _get_domain_address
. What other error do you think it should raise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(suggestion, non-blocking) DomainAddress
no longer re-creates deleted DomainAddress:
fx-private-relay/emails/validators.py
Line 75 in 4cde843
def valid_address(address: str, domain: str, subdomain: str | None = None) -> bool: |
If we are handling for getting a complaint on a DomainAddress
or RelayAddress
that never existed I think throwing a SuspiciousOperations or ValidationError so it is not responding with bad request and separately handle and log in _disable_masks_for_complaint
as:
logger.error(
"Received a complaint from a destination address that never existed as "
"a Relay address.",
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for cleaning up the code. I still think _handle_complaint
could be better. I'd support the get_address
rename instead of the new parameter, if you are ambitious.
Also, the expected email goes to no one, which is either a bug in the new code or the test setup, and should be fixed.
I made 75e4d85 to address #5045 (comment). Need to dig into #5045 (comment). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the blank "To" is problematic, but we're also behind a feature flag, so I'm OK getting some code into main
and iterating.
…ents loop To ensure the Relay mask belongs to the user from whom we received the spam complaint, moves _disable_masks_for_complaint() into complained_recipients loop. Also, change _disable_masks_for_complaint to search the original mail "source" field for a Relay mask address to find the mask thru which the spam email was sent.
75e4d85
to
ab264a3
Compare
…real email address
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with what @jwhitlock said about this being behind a feature flag, so I'm OK getting some code into main and iterating. But I made some suggestions that can be included now or in the future.
Scope creep UX idea:
I am wondering if it would be helpful to mention how many emails were blocked for the address when the service automatically blocks the email so the user can know they are getting more emails from that mask and make decision to re-enable it later.
emails/views.py
Outdated
try: | ||
address = _get_address(mask_address, False) | ||
# ensure the mask belongs to the user for whom Relay received a complaint | ||
if address.user != user: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if address.user != user: | |
if address.user != user or address.enabled == False: |
(suggestion, non-blocking) Should we send the disabled mask email if the mask was already set to blocked? This can happen when when complaints was filed after the mask was already set to block by us or by the user.
emails/views.py
Outdated
def _disable_masks_for_complaint(message_json: dict) -> None: | ||
for destination_address in message_json.get("mail", {}).get("destination", []): | ||
try: | ||
address = _get_address(destination_address, False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(suggestion, non-blocking) DomainAddress
no longer re-creates deleted DomainAddress:
fx-private-relay/emails/validators.py
Line 75 in 4cde843
def valid_address(address: str, domain: str, subdomain: str | None = None) -> bool: |
If we are handling for getting a complaint on a DomainAddress
or RelayAddress
that never existed I think throwing a SuspiciousOperations or ValidationError so it is not responding with bad request and separately handle and log in _disable_masks_for_complaint
as:
logger.error(
"Received a complaint from a destination address that never existed as "
"a Relay address.",
)
Disable mask on complaint notification
See https://mozilla-hub.atlassian.net/browse/MPP-3119 for more context.
When a user (or their email provider) marks a Relay email as spam, we receive a complaint notification. To prevent further spam from reaching the user (causing more complaints), we want to disable the email mask that forwarded the spam email, and notify the user.
Screenshot (if applicable)
How to test
This will be hard to test until it's on a server with fully operational AWS SES. When it is:
disable_mask_on_complaint
flag for the userChecklist (Definition of Done)
[x] I've added or updated relevant docs in the docs/ directory/frontend/src/styles/tokens.scss
).