Merge pull request #963 from simple-login/ac-complaints
Handle complaints that have multiple recipients
This commit is contained in:
commit
2adcbf52be
|
@ -105,6 +105,15 @@ We cannot use the local database to generate migration script as the local datab
|
|||
It is created via `db.create_all()` (cf `fake_data()` method). This is convenient for development and
|
||||
unit tests as we don't have to wait for the migration.
|
||||
|
||||
## Reset database
|
||||
|
||||
There are two scripts to reset your local db to an empty state:
|
||||
|
||||
- `scripts/reset_local_db.sh` will reset your development db to the latest migration version and add the development data needed to run the
|
||||
server.py locally.
|
||||
- `scripts/reset_test_db.sh` will reset your test db to the latest migration without adding the dev server data to prevent interferring with
|
||||
the tests.
|
||||
|
||||
## Code structure
|
||||
|
||||
The repo consists of the three following entry points:
|
||||
|
|
|
@ -19,6 +19,7 @@ DKIM_SIGNATURE = "DKIM-Signature"
|
|||
X_SPAM_STATUS = "X-Spam-Status"
|
||||
LIST_UNSUBSCRIBE = "List-Unsubscribe"
|
||||
LIST_UNSUBSCRIBE_POST = "List-Unsubscribe-Post"
|
||||
RETURN_PATH = "Return-Path"
|
||||
|
||||
# headers used to DKIM sign in order of preference
|
||||
DKIM_HEADERS = [
|
||||
|
@ -50,3 +51,6 @@ MIME_HEADERS = [h.lower() for h in MIME_HEADERS]
|
|||
# according to https://datatracker.ietf.org/doc/html/rfc3834#section-3.1.7, this header should be set to "auto-replied"
|
||||
# however on hotmail, this is set to "auto-generated"
|
||||
AUTO_SUBMITTED = "Auto-Submitted"
|
||||
|
||||
# Yahoo complaint specific header
|
||||
YAHOO_ORIGINAL_RECIPIENT = "original-rcpt-to"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import base64
|
||||
import binascii
|
||||
import enum
|
||||
import hmac
|
||||
import json
|
||||
|
@ -1322,6 +1323,20 @@ def should_ignore_bounce(mail_from: str) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def parse_address_list(address_list: str) -> List[Tuple[str, str]]:
|
||||
"""
|
||||
Parse a list of email addresses from a header in the form "ab <ab@sd.com>, cd <cd@cd.com>"
|
||||
and return a list [("ab", "ab@sd.com"),("cd", "cd@cd.com")]
|
||||
"""
|
||||
processed_addresses = []
|
||||
for split_address in address_list.split(","):
|
||||
split_address = split_address.strip()
|
||||
if not split_address:
|
||||
continue
|
||||
processed_addresses.append(parse_full_address(split_address))
|
||||
return processed_addresses
|
||||
|
||||
|
||||
def parse_full_address(full_address) -> (str, str):
|
||||
"""
|
||||
parse the email address full format and return the display name and address
|
||||
|
@ -1414,10 +1429,15 @@ def get_verp_info_from_email(email: str) -> Optional[Tuple[VerpType, int]]:
|
|||
fields = username.split(".")
|
||||
if len(fields) != 3 or fields[0] != VERP_PREFIX:
|
||||
return None
|
||||
try:
|
||||
padding = (8 - (len(fields[1]) % 8)) % 8
|
||||
payload = base64.b32decode(fields[1].encode("utf-8").upper() + (b"=" * padding))
|
||||
padding = (8 - (len(fields[2]) % 8)) % 8
|
||||
signature = base64.b32decode(fields[2].encode("utf-8").upper() + (b"=" * padding))
|
||||
signature = base64.b32decode(
|
||||
fields[2].encode("utf-8").upper() + (b"=" * padding)
|
||||
)
|
||||
except binascii.Error:
|
||||
return None
|
||||
expected_signature = hmac.new(
|
||||
VERP_EMAIL_SECRET.encode("utf-8"), payload, VERP_HMAC_ALGO
|
||||
).digest()[:8]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import uuid
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from io import BytesIO
|
||||
from mailbox import Message
|
||||
from typing import Optional
|
||||
|
@ -12,12 +13,14 @@ from app.config import (
|
|||
)
|
||||
from app.email import headers
|
||||
from app.email_utils import (
|
||||
get_header_unicode,
|
||||
parse_full_address,
|
||||
save_email_for_debugging,
|
||||
to_bytes,
|
||||
render,
|
||||
send_email_with_rate_control,
|
||||
parse_address_list,
|
||||
get_header_unicode,
|
||||
get_verp_info_from_email,
|
||||
)
|
||||
from app.log import LOG
|
||||
from app.models import (
|
||||
|
@ -30,15 +33,72 @@ from app.models import (
|
|||
Phase,
|
||||
ProviderComplaintState,
|
||||
RefusedEmail,
|
||||
VerpType,
|
||||
EmailLog,
|
||||
Mailbox,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class OriginalMessageInformation:
|
||||
sender_address: str
|
||||
rcpt_address: str
|
||||
mailbox_address: Optional[str]
|
||||
|
||||
|
||||
class ProviderComplaintOrigin(ABC):
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def get_original_message(cls, message: Message) -> Optional[Message]:
|
||||
def get_original_addresses(
|
||||
cls, message: Message
|
||||
) -> Optional[OriginalMessageInformation]:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def _get_mailbox_id(cls, return_path: Optional[str]) -> Optional[Mailbox]:
|
||||
if not return_path:
|
||||
return None
|
||||
_, return_path = parse_full_address(get_header_unicode(return_path))
|
||||
verp_type, email_log_id = get_verp_info_from_email(return_path)
|
||||
if verp_type == VerpType.transactional:
|
||||
return None
|
||||
email_log = EmailLog.get_by(id=email_log_id)
|
||||
if email_log:
|
||||
return email_log.mailbox.email
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def sanitize_addresses_and_extract_mailbox_id(
|
||||
cls, rcpt_header: Optional[str], message: Message
|
||||
) -> Optional[OriginalMessageInformation]:
|
||||
"""
|
||||
If the rcpt_header is not None, use it as the valid rcpt address, otherwise try to extract it from the To header
|
||||
of the original message, since in the original message there can be more than one recipients.
|
||||
There can only be one sender so that one can safely be extracted from the message headers.
|
||||
"""
|
||||
try:
|
||||
if not rcpt_header:
|
||||
rcpt_header = message[headers.TO]
|
||||
rcpt_list = parse_address_list(get_header_unicode(rcpt_header))
|
||||
if not rcpt_list:
|
||||
saved_file = save_email_for_debugging(message, "NoRecipientComplaint")
|
||||
LOG.w(f"Cannot find rcpt. Saved to {saved_file or 'nowhere'}")
|
||||
return None
|
||||
rcpt_address = rcpt_list[0][1]
|
||||
_, sender_address = parse_full_address(
|
||||
get_header_unicode(message[headers.FROM])
|
||||
)
|
||||
|
||||
return OriginalMessageInformation(
|
||||
sender_address,
|
||||
rcpt_address,
|
||||
cls._get_mailbox_id(message[headers.RETURN_PATH]),
|
||||
)
|
||||
except ValueError:
|
||||
saved_file = save_email_for_debugging(message, "ComplaintOriginalAddress")
|
||||
LOG.w(f"Cannot parse from header. Saved to {saved_file or 'nowhere'}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def name(cls):
|
||||
|
@ -58,6 +118,32 @@ class ProviderComplaintYahoo(ProviderComplaintOrigin):
|
|||
return part
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_feedback_report(cls, message: Message) -> Optional[Message]:
|
||||
"""
|
||||
Find a report that yahoo embeds in the complaint. It has content type 'message/feedback-report'
|
||||
"""
|
||||
for part in message.walk():
|
||||
if part["content-type"] == "message/feedback-report":
|
||||
content = part.get_payload()
|
||||
if not content:
|
||||
continue
|
||||
return content[0]
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_original_addresses(
|
||||
cls, message: Message
|
||||
) -> Optional[OriginalMessageInformation]:
|
||||
"""
|
||||
Try to get the proper recipient from the report that yahoo adds as a port of the complaint. If we cannot find
|
||||
the rcpt in the report or we can't find the report, use the first address in the original message from
|
||||
"""
|
||||
report = cls.get_feedback_report(message)
|
||||
original = cls.get_original_message(message)
|
||||
rcpt_header = report[headers.YAHOO_ORIGINAL_RECIPIENT]
|
||||
return cls.sanitize_addresses_and_extract_mailbox_id(rcpt_header, original)
|
||||
|
||||
@classmethod
|
||||
def name(cls):
|
||||
return "yahoo"
|
||||
|
@ -76,6 +162,17 @@ class ProviderComplaintHotmail(ProviderComplaintOrigin):
|
|||
return part
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_original_addresses(
|
||||
cls, message: Message
|
||||
) -> Optional[OriginalMessageInformation]:
|
||||
"""
|
||||
Try to get the proper recipient from original x-simplelogin-envelope-to header we add on delivery.
|
||||
If we can't find the header, use the first address in the original message from"""
|
||||
original = cls.get_original_message(message)
|
||||
rcpt_header = original[headers.SL_ENVELOPE_TO]
|
||||
return cls.sanitize_addresses_and_extract_mailbox_id(rcpt_header, original)
|
||||
|
||||
@classmethod
|
||||
def name(cls):
|
||||
return "hotmail"
|
||||
|
@ -98,60 +195,55 @@ def find_alias_with_address(address: str) -> Optional[Alias]:
|
|||
|
||||
|
||||
def handle_complaint(message: Message, origin: ProviderComplaintOrigin) -> bool:
|
||||
original_message = origin.get_original_message(message)
|
||||
|
||||
try:
|
||||
_, to_address = parse_full_address(
|
||||
get_header_unicode(original_message[headers.TO])
|
||||
)
|
||||
_, from_address = parse_full_address(
|
||||
get_header_unicode(original_message[headers.FROM])
|
||||
)
|
||||
except ValueError:
|
||||
saved_file = save_email_for_debugging(message, "FromParseFailed")
|
||||
LOG.w(f"Cannot parse from header. Saved to {saved_file or 'nowhere'}")
|
||||
msg_info = origin.get_original_addresses(message)
|
||||
if not msg_info:
|
||||
return False
|
||||
|
||||
user = User.get_by(email=to_address)
|
||||
user = User.get_by(email=msg_info.rcpt_address)
|
||||
if user:
|
||||
LOG.d(f"Handle provider {origin.name()} complaint for {user}")
|
||||
report_complaint_to_user_in_transactional_phase(user, origin)
|
||||
report_complaint_to_user_in_transactional_phase(user, origin, msg_info)
|
||||
return True
|
||||
|
||||
alias = find_alias_with_address(from_address)
|
||||
alias = find_alias_with_address(msg_info.sender_address)
|
||||
# the email is during a reply phase, from=alias and to=destination
|
||||
if alias:
|
||||
LOG.i(
|
||||
f"Complaint from {origin.name} during reply phase {alias} -> {to_address}, {user}"
|
||||
f"Complaint from {origin.name} during reply phase {alias} -> {msg_info.rcpt_address}, {user}"
|
||||
)
|
||||
report_complaint_to_user_in_reply_phase(
|
||||
alias, msg_info.rcpt_address, origin, msg_info
|
||||
)
|
||||
report_complaint_to_user_in_reply_phase(alias, to_address, origin)
|
||||
store_provider_complaint(alias, message)
|
||||
return True
|
||||
|
||||
contact = Contact.get_by(reply_email=from_address)
|
||||
contact = Contact.get_by(reply_email=msg_info.sender_address)
|
||||
if contact:
|
||||
alias = contact.alias
|
||||
else:
|
||||
alias = find_alias_with_address(to_address)
|
||||
alias = find_alias_with_address(msg_info.rcpt_address)
|
||||
|
||||
if not alias:
|
||||
LOG.e(
|
||||
f"Cannot find alias from address {to_address} or contact with reply {from_address}"
|
||||
f"Cannot find alias for address {msg_info.rcpt_address} or contact with reply {msg_info.sender_address}"
|
||||
)
|
||||
return False
|
||||
|
||||
report_complaint_to_user_in_forward_phase(alias, origin)
|
||||
report_complaint_to_user_in_forward_phase(alias, origin, msg_info)
|
||||
return True
|
||||
|
||||
|
||||
def report_complaint_to_user_in_reply_phase(
|
||||
alias: Alias, to_address: str, origin: ProviderComplaintOrigin
|
||||
alias: Alias,
|
||||
to_address: str,
|
||||
origin: ProviderComplaintOrigin,
|
||||
msg_info: OriginalMessageInformation,
|
||||
):
|
||||
capitalized_name = origin.name().capitalize()
|
||||
send_email_with_rate_control(
|
||||
alias.user,
|
||||
f"{ALERT_COMPLAINT_REPLY_PHASE}_{origin.name()}",
|
||||
alias.user.email,
|
||||
msg_info.mailbox_address or alias.mailbox.email,
|
||||
f"Abuse report from {capitalized_name}",
|
||||
render(
|
||||
"transactional/provider-complaint-reply-phase.txt.jinja2",
|
||||
|
@ -166,13 +258,13 @@ def report_complaint_to_user_in_reply_phase(
|
|||
|
||||
|
||||
def report_complaint_to_user_in_transactional_phase(
|
||||
user: User, origin: ProviderComplaintOrigin
|
||||
user: User, origin: ProviderComplaintOrigin, msg_info: OriginalMessageInformation
|
||||
):
|
||||
capitalized_name = origin.name().capitalize()
|
||||
send_email_with_rate_control(
|
||||
user,
|
||||
f"{ALERT_COMPLAINT_TRANSACTIONAL_PHASE}_{origin.name()}",
|
||||
user.email,
|
||||
msg_info.mailbox_address or user.email,
|
||||
f"Abuse report from {capitalized_name}",
|
||||
render(
|
||||
"transactional/provider-complaint-to-user.txt.jinja2",
|
||||
|
@ -190,23 +282,24 @@ def report_complaint_to_user_in_transactional_phase(
|
|||
|
||||
|
||||
def report_complaint_to_user_in_forward_phase(
|
||||
alias: Alias, origin: ProviderComplaintOrigin
|
||||
alias: Alias, origin: ProviderComplaintOrigin, msg_info: OriginalMessageInformation
|
||||
):
|
||||
capitalized_name = origin.name().capitalize()
|
||||
user = alias.user
|
||||
mailbox_email = msg_info.mailbox_address or alias.mailbox.email
|
||||
send_email_with_rate_control(
|
||||
user,
|
||||
f"{ALERT_COMPLAINT_FORWARD_PHASE}_{origin.name()}",
|
||||
user.email,
|
||||
mailbox_email,
|
||||
f"Abuse report from {capitalized_name}",
|
||||
render(
|
||||
"transactional/provider-complaint-forward-phase.txt.jinja2",
|
||||
user=user,
|
||||
email=mailbox_email,
|
||||
provider=capitalized_name,
|
||||
),
|
||||
render(
|
||||
"transactional/provider-complaint-forward-phase.html",
|
||||
user=user,
|
||||
email=mailbox_email,
|
||||
provider=capitalized_name,
|
||||
),
|
||||
max_nb_alert=1,
|
||||
|
|
7
scripts/reset_local_db.sh
Executable file
7
scripts/reset_local_db.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
export DB_URI=postgresql://myuser:mypassword@localhost:15432/simplelogin
|
||||
echo 'drop schema public cascade; create schema public;' | psql $DB_URI
|
||||
|
||||
poetry run alembic upgrade head
|
||||
poetry run flask dummy-data
|
6
scripts/reset_test_db.sh
Executable file
6
scripts/reset_test_db.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
export DB_URI=postgresql://myuser:mypassword@localhost:15432/test
|
||||
echo 'drop schema public cascade; create schema public;' | psql $DB_URI
|
||||
|
||||
poetry run alembic upgrade head
|
|
@ -6,7 +6,7 @@
|
|||
{% endcall %}
|
||||
|
||||
{% call text() %}
|
||||
{{ provider }} has informed us about an email sent to <b>{{ user.email }}</b> that might have been considered as spam,
|
||||
{{ provider }} has informed us about an email sent to <b>{{ email }}</b> that might have been considered as spam,
|
||||
either by you or by {{ provider }} spam filter.
|
||||
{% endcall %}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ Hi,
|
|||
|
||||
This is SimpleLogin team.
|
||||
|
||||
{{ provider }} has informed us about an email sent to {{ user.email }} that might have been considered as spam,
|
||||
{{ provider }} has informed us about an email sent to {{ email }} that might have been considered as spam,
|
||||
either by you or by {{ provider }}.
|
||||
|
||||
Please note that explicitly marking a SimpleLogin's forwarded email as Spam
|
||||
|
|
258
tests/example_emls/hotmail_complaint.eml
Normal file
258
tests/example_emls/hotmail_complaint.eml
Normal file
|
@ -0,0 +1,258 @@
|
|||
X-SimpleLogin-Client-IP: 40.92.66.13
|
||||
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=40.92.66.13;
|
||||
helo=eur01-ve1-obe.outbound.protection.outlook.com;
|
||||
envelope-from=staff@hotmail.com; receiver=<UNKNOWN>
|
||||
Received: from EUR01-VE1-obe.outbound.protection.outlook.com
|
||||
(mail-oln040092066013.outbound.protection.outlook.com [40.92.66.13])
|
||||
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
|
||||
(No client certificate requested)
|
||||
by prod4.simplelogin.co (Postfix) with ESMTPS id 408E09C472
|
||||
for <{{ postmaster }}>; Mon, 9 May 2022 13:11:34 +0000 (UTC)
|
||||
ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;
|
||||
b=V3N8KdYGgYrjs5KcjFUA0MgPUmOc+NV4ygLfSd7fehfiNemKdhe6Cpfj58zWFNzoG5qBoUCIm/BI7aCr7lqAU2hQJypTrJG+3zbSdnuCKMBVV5GHZxkE+XAeSU+4wt4xwl1ZiVx/2P//xUVWN/TVmiuKUgCn9n+WagU9LYGVT9z6wwOpXggpDf6ow9RnJDPJpkakHRh7rQPABbrOpVqEZnoJdAH5mgdTHJOeBumNym4i3GKnky+IfMlqwGcbTrzgrt/D3PpZdsMG4B+jEHtTo3FgB9JY+abjU9Bvn4rXwKr3RMF+1ZV3UsznQVwuT99PtfEcExV3zSsqEPDBy9QT9w==
|
||||
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;
|
||||
s=arcselector9901;
|
||||
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;
|
||||
bh=Y37p6EaXY5hpBNgMr1ILYzy35GKdkqWXm69FR2RyQgA=;
|
||||
b=aet1P4fpmUM9bqbLD3vtp/EWfUi2WfvWbOnnLg/YZ2vxoTF/eM5IHDBB/I7btdzZICric+KkhRih/kvaVURGy4jybYjn9FNfT+HShTJa75Pk30fp3in/5lL2x6Q0xM0Naf9YtTvGgqlLDrdgCmktxyByNAOFPo27fEWy3fk/00IPWyI8j77VvYsGn8rJCLbhDUBWwGzQ9P7SabIqn9Ybx6CKcw2FssJhSNAyOIx7EkrGxq8y/5dXeWSHLFBdHPu6F9w/DKyt9cv17rBSnHo4tx1Ese93vBHT5XIwTwnGisCa0++eqL/69GugKoe5odkAfsdRAlBjVTgXp2Lol4rrpg==
|
||||
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
|
||||
dkim=none; arc=none
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hotmail.com;
|
||||
s=selector1;
|
||||
h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
|
||||
bh=Y37p6EaXY5hpBNgMr1ILYzy35GKdkqWXm69FR2RyQgA=;
|
||||
b=uMkd90Lx6ikNpk7RRBU3AfQ0jjbjRZAGQLnY3r+dQ3CNnhgfHxpNRudxGDydmf6GQ2AuylmOnLVATh8XMKTvCnVg8hjB9xrxd5qPpQ3k92U5VlgVe1o1Nwq8R6VCJugOZduDjSJdBXO2ACosUul6IQXKMBpSNq+bGJ9VHu63EGTphkWOOw1a4PArg8tQTSmkpkyh788nsfNXnVsh2fkL6we1LyvagQzTS4e1ynuSk1zAk+6U5KOuhRVr2Nh/AvyvswWpjA4pflOqFwyqsMYb3N6wnpRTct8CJUPlQwEx6chiJgKNGrAkdRbnWaEyeIEdyJB/NLwtPqZzKYFgv7f8wg==
|
||||
Received: from AM6PR02CA0021.eurprd02.prod.outlook.com (2603:10a6:20b:6e::34)
|
||||
by AM0PR02MB4563.eurprd02.prod.outlook.com (2603:10a6:208:ec::33) with
|
||||
Microsoft SMTP Server (version=TLS1_2,
|
||||
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5227.22; Mon, 9 May
|
||||
2022 13:11:32 +0000
|
||||
Received: from AM6EUR05FT047.eop-eur05.prod.protection.outlook.com
|
||||
(2603:10a6:20b:6e:cafe::26) by AM6PR02CA0021.outlook.office365.com
|
||||
(2603:10a6:20b:6e::34) with Microsoft SMTP Server (version=TLS1_2,
|
||||
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5227.23 via Frontend
|
||||
Transport; Mon, 9 May 2022 13:11:32 +0000
|
||||
Received: from DM5SVC01SF077 (40.107.211.126) by
|
||||
AM6EUR05FT047.mail.protection.outlook.com (10.233.241.167) with Microsoft
|
||||
SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id
|
||||
15.20.5227.15 via Frontend Transport; Mon, 9 May 2022 13:11:32 +0000
|
||||
X-IncomingTopHeaderMarker:
|
||||
OriginalChecksum:86053024C4DD515561A96BAF61AACB6F8A4DB30C8D14CAC5F2F7D189ACDCA109;UpperCasedChecksum:5323AB267D58619B82076460438A30DFDD8E7969870D76B723156F921928319B;SizeAsReceived:257;Count:6
|
||||
Date: Mon, 9 May 2022 13:10:08 +0000
|
||||
From: <staff@hotmail.com>
|
||||
Subject: complaint about message from 176.119.200.162
|
||||
To: {{ postmaster }}
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="31A9507D-D0B3-4DCD-AFBB-413468892CFE"
|
||||
X-IncomingHeaderCount: 6
|
||||
Message-ID:
|
||||
<1d63d9ee-8f3e-4876-955c-1807db5ad138@AM6EUR05FT047.eop-eur05.prod.protection.outlook.com>
|
||||
X-EOPAttributedMessage: 0
|
||||
X-MS-PublicTrafficType: Email
|
||||
X-MS-Office365-Filtering-Correlation-Id: 44e9ec0b-6c5d-4cea-6417-08da31bd7000
|
||||
X-MS-TrafficTypeDiagnostic: AM0PR02MB4563:EE_
|
||||
X-Microsoft-Antispam: BCL:0;
|
||||
X-Microsoft-Antispam-Message-Info:
|
||||
lK5xD4UZS47NfR0tHc3wEp4HHOifZ4SDBb8aKx7H/vEW8Rg8rXXH12G4lWdpzr8qTsCmvzuhj5x6IAumOKQ8lWLj5Lp3jyml91wVnwCtUnk5cTXpQwDZd9QMgtEW07GoLdWjkbShAhLRDf+9Y4DxidHCacOAYxcNX42wo3vYZOEHDzVRUxSmY0c7Km60pDtiYzEk+P9AoE2YKYG2rDwDx0vgoLgqFspGqQ+2OeHD2ZAEyATHR/sQy6tf5S2d4wA3HcHrwrGMlz/4d9VbT5h9a5cqj9S59wpuc6g8nyYhmK3AHJkB5nXmpBZBihTw5X/Qh5PZqUYwPxkwpq3WlaEuXvzaKFiwJFvtuRGX+mEioClCxiwPROb7sI9ZHWPw48AHysF+whYGBfleRy4c2SuW6e1D5uewGry+lXVljxg7qKo=
|
||||
X-OriginatorOrg: sct-15-20-4755-11-msonline-outlook-ab7de.templateTenant
|
||||
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 May 2022 13:11:32.0875
|
||||
(UTC)
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id:
|
||||
44e9ec0b-6c5d-4cea-6417-08da31bd7000
|
||||
X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa
|
||||
X-MS-Exchange-CrossTenant-AuthSource:
|
||||
AM6EUR05FT047.eop-eur05.prod.protection.outlook.com
|
||||
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
|
||||
X-MS-Exchange-CrossTenant-FromEntityHeader: Internet
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg:
|
||||
00000000-0000-0000-0000-000000000000
|
||||
X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR02MB4563
|
||||
X-Spamd-Result: default: False [-1.75 / 13.00];
|
||||
ARC_ALLOW(-1.00)[microsoft.com:s=arcselector9901:i=1];
|
||||
DMARC_POLICY_ALLOW(-0.50)[hotmail.com,none];
|
||||
R_SPF_ALLOW(-0.20)[+ip4:40.92.0.0/15];
|
||||
MIME_HTML_ONLY(0.20)[];
|
||||
R_DKIM_ALLOW(-0.20)[hotmail.com:s=selector1];
|
||||
MIME_GOOD(-0.10)[multipart/mixed,multipart/related];
|
||||
MANY_INVISIBLE_PARTS(0.05)[1];
|
||||
NEURAL_HAM(-0.00)[-0.996];
|
||||
FROM_EQ_ENVFROM(0.00)[];
|
||||
FREEMAIL_ENVFROM(0.00)[hotmail.com];
|
||||
MIME_TRACE(0.00)[0:+,1:~,2:+,3:+,4:~];
|
||||
ASN(0.00)[asn:8075, ipnet:40.80.0.0/12, country:US];
|
||||
RCVD_IN_DNSWL_NONE(0.00)[40.92.66.13:from];
|
||||
DKIM_TRACE(0.00)[hotmail.com:+];
|
||||
RCVD_TLS_LAST(0.00)[];
|
||||
TO_MATCH_ENVRCPT_ALL(0.00)[];
|
||||
FREEMAIL_FROM(0.00)[hotmail.com];
|
||||
FROM_NO_DN(0.00)[];
|
||||
TO_DN_NONE(0.00)[];
|
||||
RCVD_COUNT_THREE(0.00)[4];
|
||||
RCPT_COUNT_ONE(0.00)[1];
|
||||
DWL_DNSWL_NONE(0.00)[hotmail.com:dkim]
|
||||
X-Rspamd-Queue-Id: 408E09C472
|
||||
X-Rspamd-Server: prod4
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
--31A9507D-D0B3-4DCD-AFBB-413468892CFE
|
||||
Content-Type: message/rfc822
|
||||
Content-Disposition: inline
|
||||
|
||||
X-HmXmrOriginalRecipient: <jan.bailey2934@outlook.com>
|
||||
X-MS-Exchange-EOPDirect: true
|
||||
Received: from SJ0PR11MB4958.namprd11.prod.outlook.com (2603:10b6:a03:2ae::24)
|
||||
by SA0PR11MB4525.namprd11.prod.outlook.com with HTTPS; Mon, 9 May 2022
|
||||
04:30:48 +0000
|
||||
Received: from BN9PR03CA0117.namprd03.prod.outlook.com (2603:10b6:408:fd::32)
|
||||
by SJ0PR11MB4958.namprd11.prod.outlook.com (2603:10b6:a03:2ae::24) with
|
||||
Microsoft SMTP Server (version=TLS1_2,
|
||||
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5227.20; Mon, 9 May
|
||||
2022 04:30:45 +0000
|
||||
Received: from BN8NAM11FT053.eop-nam11.prod.protection.outlook.com
|
||||
(2603:10b6:408:fd:cafe::d0) by BN9PR03CA0117.outlook.office365.com
|
||||
(2603:10b6:408:fd::32) with Microsoft SMTP Server (version=TLS1_2,
|
||||
cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5227.20 via Frontend
|
||||
Transport; Mon, 9 May 2022 04:30:45 +0000
|
||||
Authentication-Results: spf=pass (sender IP is 176.119.200.162)
|
||||
smtp.mailfrom=simplelogin.co; dkim=pass (signature was verified)
|
||||
header.d=simplelogin.co;dmarc=pass action=none
|
||||
header.from=simplelogin.co;compauth=pass reason=100
|
||||
Received-SPF: Pass (protection.outlook.com: domain of simplelogin.co
|
||||
designates 176.119.200.162 as permitted sender)
|
||||
receiver=protection.outlook.com; client-ip=176.119.200.162;
|
||||
helo=mail-200162.simplelogin.co;
|
||||
Received: from mail-200162.simplelogin.co (176.119.200.162) by
|
||||
BN8NAM11FT053.mail.protection.outlook.com (10.13.177.209) with Microsoft SMTP
|
||||
Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
|
||||
15.20.5227.15 via Frontend Transport; Mon, 9 May 2022 04:30:44 +0000
|
||||
X-IncomingTopHeaderMarker:
|
||||
OriginalChecksum:5EBD8C309CA888838EDC898C63E28E1EC00EF74772276A54C08DA83D658756F4;UpperCasedChecksum:E102374CD208D4ACB2034F1A17F76DA6345BD176395C6D4EADEC3B47BFF41ECC;SizeAsReceived:1262;Count:15
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=simplelogin.co;
|
||||
s=dkim; t=1652070640; h=From:To:Subject:Message-ID:Date;
|
||||
bh=Tu2Q0oO5GuGw4CVxDAdixtRKr6jqMWjpH9zEf50uKwg=;
|
||||
b=o6I0Ij1CahU9EUj/9uwWJpsDjfi/2gQIXT0KJT6IAK9hOoJ5bVqPsqtyGTfIoqYhhtD/ic
|
||||
5NybKJmB6B6KL5hl5LG3KzCdaWfe3dAAhD4e2gIU80dal596dlzluyvLR1k+6rdM4JvlGq
|
||||
OVWLR42Oj4anrnOqLCUkL44ILIhLpAE=
|
||||
Date: Mon, 9 May 2022 00:30:38 -0400 (EDT)
|
||||
Message-ID:
|
||||
<10627474.1041327707.1652070638478.JavaMail.cloud@p2-mta-0301.p2.messagegears.net>
|
||||
Subject: Original Subject
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_1041327705_575167926.1652070638478"
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-SimpleLogin-Type: Forward
|
||||
X-SimpleLogin-EmailLog-ID: 832832
|
||||
X-SimpleLogin-Envelope-To: {{ rcpt }}
|
||||
From: {{ sender }}
|
||||
Reply-To: {{ sender }}
|
||||
To: {{ rcpt_comma_list }}
|
||||
List-Unsubscribe: <mailto:unsubscribe@simplelogin.co?subject=3134388=>
|
||||
X-SimpleLogin-Want-Signing: yes
|
||||
X-IncomingHeaderCount: 15
|
||||
Return-Path: {{ return_path }}
|
||||
X-MS-Exchange-Organization-ExpirationStartTime: 09 May 2022 04:30:45.1195
|
||||
(UTC)
|
||||
X-MS-Exchange-Organization-ExpirationStartTimeReason: OriginalSubmit
|
||||
X-MS-Exchange-Organization-ExpirationInterval: 1:00:00:00.0000000
|
||||
X-MS-Exchange-Organization-ExpirationIntervalReason: OriginalSubmit
|
||||
X-MS-Exchange-Organization-Network-Message-Id:
|
||||
ede92e41-5acb-4474-c5be-08da3174af2b
|
||||
X-EOPAttributedMessage: 0
|
||||
X-EOPTenantAttributedMessage: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa:0
|
||||
X-MS-Exchange-Organization-MessageDirectionality: Incoming
|
||||
X-MS-PublicTrafficType: Email
|
||||
X-MS-Exchange-Organization-AuthSource:
|
||||
BN8NAM11FT053.eop-nam11.prod.protection.outlook.com
|
||||
X-MS-Exchange-Organization-AuthAs: Anonymous
|
||||
X-MS-UserLastLogonTime: 5/9/2022 3:30:52 AM
|
||||
X-MS-Office365-Filtering-Correlation-Id: ede92e41-5acb-4474-c5be-08da3174af2b
|
||||
X-MS-TrafficTypeDiagnostic: SJ0PR11MB4958:EE_
|
||||
X-MS-Exchange-EOPDirect: true
|
||||
X-Sender-IP: 176.119.200.162
|
||||
X-SID-PRA: PHWNQHFTTLQNZJXKMLHZCSKLLLJXMGEJOEOWW@SIMPLELOGIN.CO
|
||||
X-SID-Result: PASS
|
||||
X-MS-Exchange-Organization-PCL: 2
|
||||
X-MS-Exchange-Organization-SCL: 1
|
||||
X-Microsoft-Antispam: BCL:0;
|
||||
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 May 2022 04:30:44.9945
|
||||
(UTC)
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id:
|
||||
ede92e41-5acb-4474-c5be-08da3174af2b
|
||||
X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa
|
||||
X-MS-Exchange-CrossTenant-AuthSource:
|
||||
BN8NAM11FT053.eop-nam11.prod.protection.outlook.com
|
||||
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
|
||||
X-MS-Exchange-CrossTenant-FromEntityHeader: Internet
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg:
|
||||
00000000-0000-0000-0000-000000000000
|
||||
X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR11MB4958
|
||||
X-MS-Exchange-Transport-EndToEndLatency: 00:00:03.3271765
|
||||
X-MS-Exchange-Processed-By-BccFoldering: 15.20.5227.023
|
||||
X-Microsoft-Antispam-Mailbox-Delivery:
|
||||
abwl:0;wl:0;pcwl:0;kl:0;iwl:0;ijl:0;dwl:0;dkl:0;rwl:0;ucf:0;jmr:0;ex:0;auth:1;dest:I;ENG:(5062000285)(90000117)(90005022)(91005020)(91035115)(5061607266)(5061608174)(9050020)(9100338)(2008001134)(2008000189)(2008120399)(2008019284)(2008021020)(8390246)(8377080)(8386120)(4810004)(4910013)(9910022)(9510006)(10110021)(9320005);
|
||||
X-Message-Info:
|
||||
5vMbyqxGkdcvoPRAk5ACFywqndfpuBMcVz6K/12RtMALmdfGi+GpgO+lXQe3PiGwHtV5wXFRStQwg29XySZZo6tOyvshTSJ1uafhX53S93r5MaqDxJrR0UNGr2VYdKiAm1jYIYQm84v/mEbSAGjjBwEgS1PHlzM72I96JadXzfV9Fmsd5pHlfoLxEqXe6hBJAAQS99CcpwPDnaVA9UZUHA==
|
||||
X-Message-Delivery: Vj0xLjE7dXM9MDtsPTA7YT0wO0Q9MTtHRD0xO1NDTD0tMQ==
|
||||
X-Microsoft-Antispam-Message-Info:
|
||||
=?utf-8?B?VjZIQkpKR05oRUo1Vzc0YTBDUW52S0lsYkJSMGRzY0hJMnRMOWdyRGowcGpk?=
|
||||
=?utf-8?B?SUJLSDRPaStzakpJUHlaWVFnNWpBSGRsZ1Z4aEFmaXJOR1ZMUWxTTnQ1SXg1?=
|
||||
=?utf-8?B?anhFNTJ5RGU2YjRiTWhWK3FvWXBJU29YSWdqM3VvUkZpY21aaW5lSkJ5WWph?=
|
||||
=?utf-8?B?L2pxclptbVBGdm02emlHT3ZBQ1BHZTcrM0c3NmJ5alJLSGlaYVMvK0hwVmJV?=
|
||||
=?utf-8?B?eHlTU2grSElBTVY5cXF2d250OXBmQ2pzeEVUWTlSZ1hCc1dEdStXMzFGcWlO?=
|
||||
=?utf-8?B?VytUeEgyRWl5a2U1Y09VKyt3am9ZQVYrRm1LUkhRRGdKbkFTaHc4RTErQ1c0?=
|
||||
=?utf-8?B?RjBNVllEVW9UakJIQm5FWWVYd2RuaENZTVJIUkI4RmlheWsyajZmanFCUlpt?=
|
||||
=?utf-8?B?ZTJYZlg1RGxkbEVlRk0zallRWStiU1Z1QmJlTmtKS3J5MmZuOFk2blRHemEw?=
|
||||
=?utf-8?B?OVhkUUhWWTAzV2dySnMra1pKMGo1Zy8xSFNuemx4Slg1ckhDcitmVGRHSDBW?=
|
||||
=?utf-8?B?MFlOMDFtNmRPTDVSL3BGU0VNNWRObGVkUUlRcG9MSUJFeVBFcGtlVENSZmIr?=
|
||||
=?utf-8?B?V3F6by8vOHBROWplTi9JdWtEVDFwUVZsdVk5djBtN0wzbk04RG56RjRsM1ZH?=
|
||||
=?utf-8?B?cytsajBZNUNwUXk5SVRFZXhMejN3anYweGpCWkltQ2lwQnA3V1B6UUt0VUw1?=
|
||||
=?utf-8?B?dXpLQ3hxemNQNWRGWmpqZi9BY2EzOTAwQ3h5RlF2RHQyVG1McWp6N1JXUWRY?=
|
||||
=?utf-8?B?TjlCRWFmNFhQSitwSTk2cEhPK1N3ZVQxbktlMWFwa05hNGllOVpCc2Q3MUEy?=
|
||||
=?utf-8?B?TlBHVE9YUE8xRUk3dndyNkFQVlhhN3JIMnUxL25pZ3JaM1hFS0VUOXNqT2NF?=
|
||||
=?utf-8?B?Y3lFcUM0dDVuOGhTdmJ1RjJJK2sxZGViOUU2SE1DTUZ1c0pSSlNsazdPWHJ5?=
|
||||
=?utf-8?B?TXo0dUUrZEhqaVpGTHNTUnNUTUl2L2hZeFhoNUVtcmJPQ0lXYnV5Yy8rSXBq?=
|
||||
=?utf-8?B?bjYwVlBET0ErZkQ4KzJsQmM5b0hUTXJSSWlhdXlNeTZ2a0xlaHp5ZTZRQnox?=
|
||||
=?utf-8?B?T2h2NkZKNmpLcDg4TCs5ckdoU3d5aEc1Q1FYUFdTOXhxcFJsaTdtZkVuNG1W?=
|
||||
=?utf-8?B?SkVsN2llT3FpTnB6Q3lMbDR4ZzVzblhLVWw3VkpJblRQQVA4cDd1aGdtbll4?=
|
||||
=?utf-8?B?U2RWQXplZjRreWhJRnQwWGhWT2pnVmxwTW9hdUxwRE9VaTJqd1lqenh3T2pK?=
|
||||
=?utf-8?B?R2ZMaDJmNm1lS25TNU56ODFBcnc1TUZQbi9pZ0hnampKNUl0MzVQRG5wenZH?=
|
||||
=?utf-8?B?dTdrcTA4VXUwZmdNaXBKMnVsY1phOEtLUEZWMzNnUlVxYXhrRDFUN3FFN0lZ?=
|
||||
=?utf-8?B?MnVzbmhVQ2kvQVkzZ3NBQnNGL0NCNlZTbmV5ZW9FVWg5dUJTbmtaQnNZemRT?=
|
||||
=?utf-8?B?cDFKUnRPU2VpNnNwM3V5eXJxMy9YbFhPYTRFSkEyTUZjSVlNaFV0UE5RbjhK?=
|
||||
=?utf-8?B?NjJmckpva2xuaGhYT2Jkb2g1U1NEaFJmQWc5bVhheGZYMXY1b2toaVRPOXNT?=
|
||||
=?utf-8?B?Y2ZhVjYyY0pnbmw4N3VneVR6bXFoRTlndE9lTzlac0JTRWFKc1BMTmNrNFMx?=
|
||||
=?utf-8?B?M0lwTXI3STZXcFNmbytNcFB2VzJFSFpLSWFpbjlzcVlVRHk3RTFIUUQzOUlB?=
|
||||
=?utf-8?B?YnR1eC9jUnVNWlhadktVKzM5MmdmR1pBTXVxK2xzUXZ4MzNUWW5rQXZ4SXMv?=
|
||||
=?utf-8?B?RnBLUmcwT3FUWENucWtuTWhBQnl5VWFpczNGUnBkQ0ltM2ttMDM1RnFScXFa?=
|
||||
=?utf-8?B?dEtNNnF4Q1FDS2RqRTRuRkNRUC9JVTdZZ216c3hycC9ZalptbDZNZ25ydWFp?=
|
||||
=?utf-8?B?Z25qMGFLK1FQYm0vUU40OSt1SVJBTmdPTVNRN2JTVmxLTlRJMkZDeldKYWNx?=
|
||||
=?utf-8?B?VEJEVHE5ZE9QNWsxZkxrb0pFOEU5cUJvT3ArOUFDMXlZM2N4Smk5ay9qQXEv?=
|
||||
=?utf-8?B?ZXc3ZjVHMjdkcjBkN1Rodmdyd1JldkFBeDlVblRVbkxrY0xhZkIwVzBpTlNM?=
|
||||
=?utf-8?B?THAvZ01hS3NVK0dHblFFQ0h6VXYydW1QaUwzM29zcjRYRFJRTU9NZWYxQ2Nw?=
|
||||
=?utf-8?B?N1liQ3g2ZUtveTdTaW1ZSGovLzNWbWh2bDd6ZXRUR3B3eEYwakVCOS95aEs0?=
|
||||
=?utf-8?B?NkkzL1dQREVlVHFXWmE4RktDUHFENVQwYW9YWE9LS2hrMzAyVWFXTDZFVkx5?=
|
||||
=?utf-8?B?cU1nZDkzOTR1dk40SHFIcHRDSVRPajMvSVAyd0JQNDJnaVoxNmhNOFEzdzlj?=
|
||||
=?utf-8?B?ODdUNXRIVkQvTHYzMytWY2o3UHZkdUNTR1pvSVJvclVCN01EZW5pVXdRUDgx?=
|
||||
=?utf-8?B?Vmg2aUdlOUJzdXlPdXFlL01raHZSbkRONncyRlFLcGpLUFR4bm9BQXVJMHJC?=
|
||||
=?utf-8?B?cWdJSFJwZEVkZjZkOTJqZG1FNHdZRWpGdUR6R2hjdHRoMTg1Z2lpeGpnZzlH?=
|
||||
=?utf-8?B?Um5WOEJINFBFM3Evdmt4VVRCQnAwd2xBRGVralpwRnV0eUhJNTluQzFLQXI2?=
|
||||
=?utf-8?B?NXI4amV3c0ZRZEZLRjE1ZEQ3aW90Y1I0K3NPN3ZoVyt1UVdzWUpQUGh1b25N?=
|
||||
=?utf-8?Q?amuRKzTLQzIrlx9Vmv+SjIosxogY=3D?=
|
||||
MIME-Version: 1.0
|
||||
|
||||
------=_Part_1041327705_575167926.1652070638478
|
||||
Content-Type: multipart/related;
|
||||
boundary="----=_Part_1041327706_445426653.1652070638478"
|
||||
|
||||
------=_Part_1041327706_445426653.1652070638478
|
||||
Content-Type: text/html;charset=UTF-8
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
Here goes the original email content
|
||||
|
||||
------=_Part_1041327706_445426653.1652070638478--
|
||||
|
||||
------=_Part_1041327705_575167926.1652070638478--
|
||||
|
||||
--31A9507D-D0B3-4DCD-AFBB-413468892CFE--
|
157
tests/example_emls/yahoo_complaint.eml
Normal file
157
tests/example_emls/yahoo_complaint.eml
Normal file
|
@ -0,0 +1,157 @@
|
|||
X-SimpleLogin-Client-IP: 66.163.186.21
|
||||
Received-SPF: None (mailfrom) identity=mailfrom; client-ip=66.163.186.21;
|
||||
helo=sonic326-46.consmr.mail.ne1.yahoo.com;
|
||||
envelope-from=feedback@arf.mail.yahoo.com; receiver=<UNKNOWN>
|
||||
Received: from sonic326-46.consmr.mail.ne1.yahoo.com
|
||||
(sonic326-46.consmr.mail.ne1.yahoo.com [66.163.186.21])
|
||||
(using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)
|
||||
key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits)
|
||||
server-digest SHA256)
|
||||
(No client certificate requested)
|
||||
by prod4.simplelogin.co (Postfix) with ESMTPS id 160E19C47C
|
||||
for <{{ postmaster }}>; Sun, 8 May 2022 13:31:32 +0000 (UTC)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=arf.mail.yahoo.com;
|
||||
s=arf; t=1652016690; bh=y3TXlG8d2nUmz+Mm6gBEX1p1y2rwlM+LRC89Bp+HwGo=;
|
||||
h=Date:From:To:Subject:From:Subject:Reply-To;
|
||||
b=HyuY58LSzfkdH9FynjNWEl6QJeeImKRbIzrnR64sY/ggFD6fF9w1/fpXDmJ8RHpB/72llGb8nkVJkn/TK+adBCZvw4Y0SC2m8qbn6BdaC5kvAWkN6VUxvQWFMWTptAmeX+UUxY2hjEXLZQwNUd4nvvhZkbdyzw5wFSpYX0hnxAA=
|
||||
X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048;
|
||||
t=1652016690; bh=0SlXAOx+1D8SxkBJpASrTwUGjphtzchFZOSJr0X+U2m=;
|
||||
h=X-Sonic-MF:Date:From:To:Subject:From:Subject;
|
||||
b=smqcDrz5jxsmGycWk9tNncLBjcQIqBnZmsQzkJ6g8fyhQw2e30y05iTnsOBTr0S9qTPK3I2JBv0P73TH7vDAnZAnaewzj9Dymw7Z+UxXKdrPBf/tD8RGw9cX6C0eb7GUjHvbvXS03IkSGnvOPPCXLsTDXYOTflcU7A0A2L+cS9ogEBl/4AFwBf/z+lcMH20h2dZ6+wPtqPCgRY1Hf45cv4gfHrFG0a18n3BBq0doCA4cRTXeeuv06fqsUCk2GF6z0mm3YWu+umcUs16QmgjHKhy4SJHvTZfx4zFBxQEOM3hvBzriL5g0D3Rg71CdkI8TVqsyXS1YWVSQFakAw0hM+A==
|
||||
X-Sonic-MF: feedback@arf.mail.yahoo.com
|
||||
Received: from sonic.gate.mail.ne1.yahoo.com by
|
||||
sonic326.consmr.mail.ne1.yahoo.com with HTTP; Sun, 8 May 2022 13:31:30 +0000
|
||||
Date: Sun, 8 May 2022 13:31:28 +0000 (UTC)
|
||||
From: Yahoo! Mail AntiSpam Feedback <feedback@arf.mail.yahoo.com>
|
||||
To: {{ postmaster }}
|
||||
Message-ID:
|
||||
<1486688083.18136997.1652016688605@chakraconsumer2.asd.mail.ne1.yahoo.com>
|
||||
Subject: Original subject
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/report; report-type=feedback-report;
|
||||
boundary="----=_Part_18136996_1734597748.1652016688604"
|
||||
X-Yahoo-Newman-Property: cfl
|
||||
X-Yahoo-Newman-Id: cfl-test
|
||||
X-Spamd-Result: default: False [-0.65 / 13.00];
|
||||
DMARC_POLICY_ALLOW(-0.50)[yahoo.com,reject];
|
||||
R_DKIM_ALLOW(-0.20)[arf.mail.yahoo.com:s=arf];
|
||||
SUBJ_ALL_CAPS(0.15)[2];
|
||||
MIME_GOOD(-0.10)[text/plain,multipart/alternative];
|
||||
R_SPF_NA(0.00)[no SPF record];
|
||||
FROM_EQ_ENVFROM(0.00)[];
|
||||
MIME_TRACE(0.00)[0:~,1:+,2:~,3:+,4:~,5:+,6:+,7:~];
|
||||
RCVD_TLS_LAST(0.00)[];
|
||||
RCVD_IN_DNSWL_NONE(0.00)[66.163.186.21:from];
|
||||
ASN(0.00)[asn:36646, ipnet:66.163.184.0/21, country:US];
|
||||
ARC_NA(0.00)[];
|
||||
DKIM_TRACE(0.00)[arf.mail.yahoo.com:+];
|
||||
MID_RHS_MATCH_FROMTLD(0.00)[];
|
||||
TO_MATCH_ENVRCPT_ALL(0.00)[];
|
||||
FROM_HAS_DN(0.00)[];
|
||||
RCVD_COUNT_TWO(0.00)[2];
|
||||
TO_DN_NONE(0.00)[];
|
||||
RCPT_COUNT_ONE(0.00)[1];
|
||||
NEURAL_SPAM(0.00)[0.429];
|
||||
DWL_DNSWL_NONE(0.00)[yahoo.com:dkim]
|
||||
X-Rspamd-Queue-Id: 160E19C47C
|
||||
X-Rspamd-Server: prod4
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
------=_Part_18136996_1734597748.1652016688604
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: inline
|
||||
|
||||
This is an email abuse report for an email message from simplelogin.co on Sun, 8 May 2022 11:12:35 +0000
|
||||
|
||||
------=_Part_18136996_1734597748.1652016688604
|
||||
Content-Type: message/feedback-report
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: inline
|
||||
|
||||
Feedback-Type: abuse
|
||||
User-Agent: Yahoo!-Mail-Feedback/2.0
|
||||
Version: 0.1
|
||||
Original-Mail-From:
|
||||
<{{ return_path }}>
|
||||
Original-Rcpt-To: {{ rcpt }}
|
||||
Received-Date: Sun, 8 May 2022 11:12:35 +0000
|
||||
Reported-Domain: simplelogin.co
|
||||
Authentication-Results: authentication result string is not available
|
||||
|
||||
|
||||
------=_Part_18136996_1734597748.1652016688604
|
||||
Content-Type: message/rfc822
|
||||
Content-Disposition: inline
|
||||
|
||||
Received: from 10.217.151.74
|
||||
by atlas316.free.mail.ne1.yahoo.com with HTTPS;
|
||||
Sun, 8 May 2022 11:12:34 +0000
|
||||
Return-Path:
|
||||
<{{ return_path }}>
|
||||
X-Originating-Ip: [176.129.238.160]
|
||||
Received-SPF: pass (domain of simplelogin.co designates 176.119.200.160 as
|
||||
permitted sender)
|
||||
Authentication-Results: atlas316.free.mail.ne1.yahoo.com;
|
||||
dkim=pass header.i=@simplelogin.co header.s=dkim;
|
||||
spf=pass smtp.mailfrom=simplelogin.co;
|
||||
dmarc=pass(p=QUARANTINE) header.from=simplelogin.co;
|
||||
X-Apparently-To: syn_flood91@yahoo.com; Sun, 8 May 2022 11:12:35 +0000
|
||||
X-YMailISG: 5XbMksQWLDvXV9CBjagtqIT6OTC44ku5XiuZJQp_W6hhWfR.
|
||||
.wUIhFV6vRR_JeMUxC0ZAvugteAP2pe.bqk06ovvYnhJMg_HTvcmfVltbWxQ
|
||||
tK7xNSs8D2PWQdyDDzB3rdFdIIfSrQnDTGjP2xpTAqLQk3IXSuUBX7s4f8uA
|
||||
WUELPWj36_Xtqrwyj.ya4Ezw_ePzPhZGmMdCsbz2H5Jh45TLbk5HhL.TDDbH
|
||||
9Dz__HKLUC8acH0hu1vrPvo1ljzwbl_0cqlj10qMIChpB51XVDtyNA_WgWvE
|
||||
QL1hFHS0tScfRT0xATM8w8FJv1eA0ODjakDtTRgmaWBTphzeoR.FyTBj14y5
|
||||
burx6lkUqipfP7UZpNmcNDYHQdTEmdGa8JDZMX.lpM5IMOhkByIQuoTN4.Cx
|
||||
8qz9kb.o0DqxqNRgn4_fRRAoSn1xejDbzZMu.SWSvJ1KJwAfLtep37ISqNKl
|
||||
yeBeDJFMnHUjRD8B2wBB46zq4ngHFWjBGkAGQVBssLzj594FXg13aO.TnJU7
|
||||
WJ_cUSzoaH9HjgYDTi4.1x68jVxpZIEdhDe7pjLCUL2ugWdar9S7pFlyKWfa
|
||||
iTH8yQ10NXtLCwGpJ.0kgZH2WXJgyJmrq0a3j63skib7WJYtKOXfsbHV8b9e
|
||||
WxClOETCe03PtdD6G2sjEJSNFyTH_Qzzq6_21PO6kjmnEnBbibAnkiJbGhIJ
|
||||
kOSqyp_vFqstpd38vtt7iLI8L3PkyZDQXS0hB1ZCOsZqBDGJXAoWFRBtxMSd
|
||||
rMVkdvB6r8xJtn.1JrV1hpX4yRbCuEnCCPcwtGamlpyq5LG6YanKUVB868KF
|
||||
UuZ4AHFwi.m_FYHalwtfCaArtWzYybl2nQQLjPbnXxqNvfwKt3ATKFEO40ZV
|
||||
w1Ri7y.cO__09.eQHKIUNgMNeWgt.luD3thsEl0yz_ThzrCEkXDB1xAPNnLV
|
||||
tb03RulEB0xNauYTuWgKR8WJzkO4LuXMlzNAAYBQLQy_t0GoezAs7Z4oq.CH
|
||||
EfTK88cDJ7j7dXcXBi7q6g1NBZT3tyd9Bfn2DVdFaWAjWV9Lb8tir6J43MDP
|
||||
byTrZ_zJxTWKgafhOxL0gZbd5xIEZ1eHHeQO5pVZlN6FR1awozFgS4NcZu5u
|
||||
5qRtn6zHo3zNe9ORwwxqlHAEJR_5I09WYSdmTxh2QkkDQLjSlwUNV4K8jxdH
|
||||
L4ePIzNCQCt_bsGoG3uPXl8jtPD4sUWGY1lCeKAm.AHgZ.pSXXypMUpq4y14
|
||||
NihY89H61y5ZXo4Zd77shda_
|
||||
Received: from 176.119.200.160 (EHLO mail-200160.simplelogin.co)
|
||||
by 10.217.151.74 with SMTPs
|
||||
(version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256);
|
||||
Sun, 08 May 2022 11:12:34 +0000
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=simplelogin.co;
|
||||
s=dkim; t=1652008349; h=From:To:Subject:Message-ID:Date;
|
||||
bh=9HnrBUpZUe8OSXqTw1qF667IwLtHI8DqiyD0yAovIO4=;
|
||||
b=PsxiMydvEQveb20xgUvvq3DhxlLyqqoPW7sC8d/pAm8tj7T2O+7z5xxR6vVbgz823Bglzc
|
||||
djb3pRvNLgHnTozC+FiFOF8nVlWGybosn5oRfmNGkF9bhr0bJmfcDhiuC/tOaZKkod2lbf
|
||||
jQ8bqMZhCsN/xVpkMqJdNJefdkj3dP4=
|
||||
MIME-Version: 1.0
|
||||
Date: Sun, 8 May 2022 04:11:42 -0700
|
||||
Message-ID:
|
||||
<CAKGh96GHg2kuwvm4biQ-PF-4-8SPZ6JyPj-=GpoYZ6njctoRtg@mail.gmail.com>
|
||||
Subject: MF
|
||||
Content-Type: multipart/alternative; boundary="0000000000006dd95f05de7e2a70"
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-SimpleLogin-Type: Forward
|
||||
X-SimpleLogin-EmailLog-ID: 41263490
|
||||
X-SimpleLogin-Envelope-From: {{ sender }}
|
||||
X-SimpleLogin-Envelope-To: {{ rcpt }}
|
||||
From: {{ sender }}
|
||||
To: {{ rcpt_comma_list }}
|
||||
List-Unsubscribe: <mailto:unsubscribe@simplelogin.co?subject=1231546=>
|
||||
X-SimpleLogin-Want-Signing: yes
|
||||
Content-Length: 473
|
||||
|
||||
--0000000000006dd95f05de7e2a70
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
|
||||
Here goes the original email content
|
||||
|
||||
--0000000000006dd95f05de7e2a70--
|
||||
|
||||
|
||||
------=_Part_18136996_1734597748.1652016688604--
|
|
@ -1,51 +1,70 @@
|
|||
import email
|
||||
from email.message import Message
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
import pytest
|
||||
|
||||
from app.config import (
|
||||
ALERT_COMPLAINT_FORWARD_PHASE,
|
||||
ALERT_COMPLAINT_REPLY_PHASE,
|
||||
ALERT_COMPLAINT_TRANSACTIONAL_PHASE,
|
||||
POSTMASTER,
|
||||
)
|
||||
from app.db import Session
|
||||
from app.email import headers
|
||||
from app.email_utils import generate_verp_email
|
||||
from app.handler.provider_complaint import (
|
||||
handle_hotmail_complaint,
|
||||
handle_yahoo_complaint,
|
||||
)
|
||||
from app.models import Alias, ProviderComplaint, SentAlert
|
||||
from tests.utils import create_new_user
|
||||
from app.models import (
|
||||
Alias,
|
||||
ProviderComplaint,
|
||||
SentAlert,
|
||||
EmailLog,
|
||||
VerpType,
|
||||
Contact,
|
||||
)
|
||||
from tests.utils import create_new_user, load_eml_file
|
||||
|
||||
origins = [
|
||||
[handle_yahoo_complaint, "yahoo", 6],
|
||||
[handle_hotmail_complaint, "hotmail", 3],
|
||||
[handle_yahoo_complaint, "yahoo"],
|
||||
[handle_hotmail_complaint, "hotmail"],
|
||||
]
|
||||
|
||||
|
||||
def prepare_complaint(message: Message, part_num: int) -> Message:
|
||||
complaint = MIMEMultipart("related")
|
||||
# When walking, part 0 is the full message so we -1, and we want to be part N so -1 again
|
||||
for i in range(part_num - 2):
|
||||
document = MIMEText("text", "plain")
|
||||
document.set_payload(f"Part {i}")
|
||||
complaint.attach(document)
|
||||
complaint.attach(message)
|
||||
|
||||
return email.message_from_bytes(complaint.as_bytes())
|
||||
def prepare_complaint(
|
||||
provider_name: str, alias: Alias, rcpt_address: str, sender_address: str
|
||||
) -> Message:
|
||||
contact = Contact.create(
|
||||
user_id=alias.user.id,
|
||||
alias_id=alias.id,
|
||||
website_email="a@b.c",
|
||||
reply_email="d@e.f",
|
||||
commit=True,
|
||||
)
|
||||
elog = EmailLog.create(
|
||||
user_id=alias.user.id,
|
||||
mailbox_id=alias.user.default_mailbox_id,
|
||||
contact_id=contact.id,
|
||||
commit=True,
|
||||
bounced=True,
|
||||
)
|
||||
return_path = generate_verp_email(VerpType.bounce_forward, elog.id)
|
||||
return load_eml_file(
|
||||
f"{provider_name}_complaint.eml",
|
||||
{
|
||||
"postmaster": POSTMASTER,
|
||||
"return_path": return_path,
|
||||
"rcpt": rcpt_address,
|
||||
"sender": sender_address,
|
||||
"rcpt_comma_list": f"{rcpt_address},other_rcpt@somwhere.net",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("handle_ftor,provider,part_num", origins)
|
||||
def test_provider_to_user(flask_client, handle_ftor, provider, part_num):
|
||||
@pytest.mark.parametrize("handle_ftor,provider", origins)
|
||||
def test_provider_to_user(flask_client, handle_ftor, provider):
|
||||
user = create_new_user()
|
||||
original_message = Message()
|
||||
original_message[headers.TO] = user.email
|
||||
original_message[headers.FROM] = "nobody@nowhere.net"
|
||||
original_message.set_payload("Contents")
|
||||
|
||||
complaint = prepare_complaint(original_message, part_num)
|
||||
alias = Alias.create_new_random(user)
|
||||
Session.commit()
|
||||
complaint = prepare_complaint(provider, alias, user.email, "nobody@nowhere.net")
|
||||
assert handle_ftor(complaint)
|
||||
found = ProviderComplaint.filter_by(user_id=user.id).all()
|
||||
assert len(found) == 0
|
||||
|
@ -54,17 +73,12 @@ def test_provider_to_user(flask_client, handle_ftor, provider, part_num):
|
|||
assert alerts[0].alert_type == f"{ALERT_COMPLAINT_TRANSACTIONAL_PHASE}_{provider}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("handle_ftor,provider,part_num", origins)
|
||||
def test_provider_forward_phase(flask_client, handle_ftor, provider, part_num):
|
||||
@pytest.mark.parametrize("handle_ftor,provider", origins)
|
||||
def test_provider_forward_phase(flask_client, handle_ftor, provider):
|
||||
user = create_new_user()
|
||||
alias = Alias.create_new_random(user)
|
||||
Session.commit()
|
||||
original_message = Message()
|
||||
original_message[headers.TO] = "nobody@nowhere.net"
|
||||
original_message[headers.FROM] = alias.email
|
||||
original_message.set_payload("Contents")
|
||||
|
||||
complaint = prepare_complaint(original_message, part_num)
|
||||
complaint = prepare_complaint(provider, alias, "nobody@nowhere.net", alias.email)
|
||||
assert handle_ftor(complaint)
|
||||
found = ProviderComplaint.filter_by(user_id=user.id).all()
|
||||
assert len(found) == 1
|
||||
|
@ -73,17 +87,12 @@ def test_provider_forward_phase(flask_client, handle_ftor, provider, part_num):
|
|||
assert alerts[0].alert_type == f"{ALERT_COMPLAINT_REPLY_PHASE}_{provider}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("handle_ftor,provider,part_num", origins)
|
||||
def test_provider_reply_phase(flask_client, handle_ftor, provider, part_num):
|
||||
@pytest.mark.parametrize("handle_ftor,provider", origins)
|
||||
def test_provider_reply_phase(flask_client, handle_ftor, provider):
|
||||
user = create_new_user()
|
||||
alias = Alias.create_new_random(user)
|
||||
Session.commit()
|
||||
original_message = Message()
|
||||
original_message[headers.TO] = alias.email
|
||||
original_message[headers.FROM] = "no@no.no"
|
||||
original_message.set_payload("Contents")
|
||||
|
||||
complaint = prepare_complaint(original_message, part_num)
|
||||
complaint = prepare_complaint(provider, alias, alias.email, "no@no.no")
|
||||
assert handle_ftor(complaint)
|
||||
found = ProviderComplaint.filter_by(user_id=user.id).all()
|
||||
assert len(found) == 0
|
||||
|
|
|
@ -60,3 +60,5 @@ DMARC_CHECK_ENABLED=true
|
|||
PROTON_CLIENT_ID=to_fill
|
||||
PROTON_CLIENT_SECRET=to_fill
|
||||
PROTON_BASE_URL=https://localhost/api
|
||||
|
||||
POSTMASTER=postmaster@test.domain
|
Loading…
Reference in a new issue