django-codenerix-email 4.0.37__py2.py3-none-any.whl → 4.0.38__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codenerix_email/__init__.py +1 -1
- codenerix_email/__pycache__/__init__.cpython-310.pyc +0 -0
- codenerix_email/__pycache__/__init__.cpython-311.pyc +0 -0
- codenerix_email/management/commands/__pycache__/emails_recv.cpython-311.pyc +0 -0
- codenerix_email/management/commands/emails_recv.py +238 -4
- codenerix_email/static/codenerix_email/emailreceiveds_rows.html +3 -1
- {django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/METADATA +1 -1
- {django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/RECORD +11 -11
- {django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/LICENSE +0 -0
- {django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/WHEEL +0 -0
- {django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/top_level.txt +0 -0
codenerix_email/__init__.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
|
+
from textwrap import dedent
|
|
3
|
+
from argparse import RawTextHelpFormatter
|
|
2
4
|
|
|
3
5
|
import logging
|
|
4
6
|
|
|
@@ -31,7 +33,91 @@ from imapclient.exceptions import LoginError # noqa: E402
|
|
|
31
33
|
class Command(BaseCommand):
|
|
32
34
|
help = "Fetches new emails from the configured IMAP account."
|
|
33
35
|
|
|
36
|
+
def create_parser(self, prog_name, subcommand, **kwargs):
|
|
37
|
+
"""
|
|
38
|
+
Create and return the ArgumentParser instance for this command.
|
|
39
|
+
We are overriding this to use the RawTextHelpFormatter.
|
|
40
|
+
"""
|
|
41
|
+
parser = super().create_parser(prog_name, subcommand, **kwargs)
|
|
42
|
+
parser.formatter_class = RawTextHelpFormatter
|
|
43
|
+
return parser
|
|
44
|
+
|
|
34
45
|
def add_arguments(self, parser):
|
|
46
|
+
parser.epilog = dedent(
|
|
47
|
+
r"""
|
|
48
|
+
This command connects to the configured IMAP server, fetches new
|
|
49
|
+
emails, and saves them as ReceivedEmail objects in the database.
|
|
50
|
+
|
|
51
|
+
By default, it processes only unseen emails. You can use the
|
|
52
|
+
--all option to process all emails in the inbox.
|
|
53
|
+
|
|
54
|
+
You can filter by specific IMAP ID, Message-ID, or Tracking ID
|
|
55
|
+
using the respective options.
|
|
56
|
+
|
|
57
|
+
The --rewrite option allows overwriting existing received emails
|
|
58
|
+
with the same Message-ID.
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
# Fetch unseen emails
|
|
62
|
+
python manage.py emails_recv
|
|
63
|
+
|
|
64
|
+
# Fetch all emails
|
|
65
|
+
python manage.py emails_recv --all
|
|
66
|
+
|
|
67
|
+
# Fetch email by specific IMAP ID
|
|
68
|
+
python manage.py emails_recv --imap-id 123
|
|
69
|
+
|
|
70
|
+
# Fetch email by specific Message-ID
|
|
71
|
+
python manage.py emails_recv --message-id "<...>"
|
|
72
|
+
|
|
73
|
+
# Fetch email by specific Tracking ID
|
|
74
|
+
python manage.py emails_recv --tracking-id "uuid"
|
|
75
|
+
|
|
76
|
+
Make sure to configure the IMAP settings in your Django settings:
|
|
77
|
+
IMAP_EMAIL_HOST = "imap.example.com"
|
|
78
|
+
IMAP_EMAIL_PORT = 993
|
|
79
|
+
IMAP_EMAIL_USER = "your_username"
|
|
80
|
+
IMAP_EMAIL_PASSWORD = "your_password"
|
|
81
|
+
IMAP_EMAIL_SSL = True # (default: True)
|
|
82
|
+
IMAP_EMAIL_INBOX_FOLDER = "INBOX" # (default: "INBOX")
|
|
83
|
+
IMAP_EMAIL_FILTERS = {
|
|
84
|
+
"SUBJECT": [r".*"],
|
|
85
|
+
"FROM": [r".*"],
|
|
86
|
+
"MESSAGE-ID": [r".*"],
|
|
87
|
+
"TO": [
|
|
88
|
+
r"^bounce@becas\.com",
|
|
89
|
+
r"^bounces@becas\.com",
|
|
90
|
+
r"^no-reply@becas\.com",
|
|
91
|
+
r"^hola@becas\.com",
|
|
92
|
+
r"^tuasesor@becas\.com",
|
|
93
|
+
r"^[a-zA-Z0-9._%+-]+@becas\.com", # *@becas.com
|
|
94
|
+
],
|
|
95
|
+
"BODY_PLAIN": [r".*"],
|
|
96
|
+
"BODY_HTML": [r".*"],
|
|
97
|
+
"HEADER": [("X-Custom-Header", r".*")],
|
|
98
|
+
"BOUNCE_TYPE": ["hard", "soft"],
|
|
99
|
+
"BOUNCE_REASON": [r".*"],
|
|
100
|
+
"TRACKING_ID": True,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Filters are applied using AND logic across different fields and
|
|
104
|
+
OR logic within the same field.
|
|
105
|
+
|
|
106
|
+
The filters works as follows:
|
|
107
|
+
- SUBJECT, FROM, MESSAGE-ID, TO, BODY_PLAIN, BODY_HTML:
|
|
108
|
+
regex match (case-insensitive) against the respective field.
|
|
109
|
+
- HEADER: tuple of (header name, regex) to match specific headers.
|
|
110
|
+
- BOUNCE_TYPE: "hard" or "soft" to filter by bounce type.
|
|
111
|
+
- BOUNCE_REASON: regex to match the bounce reason.
|
|
112
|
+
- TRACKING_ID: if True, only process emails with a tracking ID.
|
|
113
|
+
|
|
114
|
+
If IMAP_EMAIL_FILTERS is not set, all emails are processed.
|
|
115
|
+
|
|
116
|
+
Note: This command marks processed emails as read (Seen) to avoid
|
|
117
|
+
reprocessing them in future runs.
|
|
118
|
+
""" # noqa: E501
|
|
119
|
+
)
|
|
120
|
+
|
|
35
121
|
# Named (optional) arguments
|
|
36
122
|
parser.add_argument(
|
|
37
123
|
"--silent",
|
|
@@ -244,6 +330,8 @@ class Command(BaseCommand):
|
|
|
244
330
|
efrom = msg.get("From")
|
|
245
331
|
eto = msg.get("To")
|
|
246
332
|
eid = msg.get("Message-ID")
|
|
333
|
+
ecc = msg.get("Cc")
|
|
334
|
+
ebc = msg.get("Bcc")
|
|
247
335
|
|
|
248
336
|
# If we can't get a Message-ID, use the IMAP ID as fallback
|
|
249
337
|
# to avoid duplicates
|
|
@@ -305,7 +393,8 @@ class Command(BaseCommand):
|
|
|
305
393
|
self.stdout.write(
|
|
306
394
|
self.style.WARNING(
|
|
307
395
|
f"Tracking ID {tracking_id} found "
|
|
308
|
-
"but no
|
|
396
|
+
f"for IMAP ID {imap_id} but no "
|
|
397
|
+
"matching sent email."
|
|
309
398
|
)
|
|
310
399
|
)
|
|
311
400
|
|
|
@@ -328,6 +417,33 @@ class Command(BaseCommand):
|
|
|
328
417
|
)
|
|
329
418
|
headers[header] = decoded_value
|
|
330
419
|
|
|
420
|
+
# Let emails pass based on filtering system
|
|
421
|
+
(filter_passed, filter_reason) = self.filter_pass(
|
|
422
|
+
subject,
|
|
423
|
+
efrom,
|
|
424
|
+
eto,
|
|
425
|
+
ecc,
|
|
426
|
+
ebc,
|
|
427
|
+
eid,
|
|
428
|
+
body_plain,
|
|
429
|
+
body_html,
|
|
430
|
+
headers,
|
|
431
|
+
bounce_type,
|
|
432
|
+
bounce_reason,
|
|
433
|
+
tracking_id,
|
|
434
|
+
)
|
|
435
|
+
if not filter_passed:
|
|
436
|
+
if self.verbose:
|
|
437
|
+
self.stdout.write(
|
|
438
|
+
self.style.NOTICE(
|
|
439
|
+
f"Skipping email with IMAP ID: {imap_id} "
|
|
440
|
+
f"(FILTER: {filter_reason})"
|
|
441
|
+
)
|
|
442
|
+
)
|
|
443
|
+
# Mark the message as read to avoid reprocessing
|
|
444
|
+
server.add_flags(imap_id, [b"\\Seen"])
|
|
445
|
+
continue
|
|
446
|
+
|
|
331
447
|
# Create EmailReceived object if doesn't exist
|
|
332
448
|
if not email_received:
|
|
333
449
|
overwriting = False
|
|
@@ -360,7 +476,12 @@ class Command(BaseCommand):
|
|
|
360
476
|
created_count += 1
|
|
361
477
|
verb = "Created"
|
|
362
478
|
|
|
479
|
+
# Show info about the processed email
|
|
363
480
|
if self.verbose:
|
|
481
|
+
if overwriting:
|
|
482
|
+
style = self.style.MIGRATE_HEADING
|
|
483
|
+
else:
|
|
484
|
+
style = self.style.WARNING
|
|
364
485
|
msg = (
|
|
365
486
|
f"{verb} email with IMAP ID: "
|
|
366
487
|
f"{imap_id} (link={tracking_id})"
|
|
@@ -371,19 +492,23 @@ class Command(BaseCommand):
|
|
|
371
492
|
)
|
|
372
493
|
bounce_reason_str = bounce_reason or "Unknown"
|
|
373
494
|
self.stdout.write(
|
|
374
|
-
|
|
495
|
+
style(
|
|
375
496
|
f"{msg} "
|
|
376
497
|
f"[{bounce_type_str} bounce, "
|
|
377
498
|
f"reason={bounce_reason_str}]"
|
|
378
499
|
)
|
|
379
500
|
)
|
|
380
501
|
else:
|
|
381
|
-
|
|
502
|
+
if overwriting:
|
|
503
|
+
style = self.style.MIGRATE_HEADING
|
|
504
|
+
else:
|
|
505
|
+
style = self.style.SUCCESS
|
|
506
|
+
self.stdout.write(style(msg))
|
|
382
507
|
|
|
383
508
|
else:
|
|
384
509
|
if self.verbose:
|
|
385
510
|
self.stdout.write(
|
|
386
|
-
self.style.
|
|
511
|
+
self.style.HTTP_INFO(
|
|
387
512
|
f"Skipping email with IMAP ID: {imap_id} (DUP)"
|
|
388
513
|
)
|
|
389
514
|
)
|
|
@@ -599,3 +724,112 @@ class Command(BaseCommand):
|
|
|
599
724
|
bounce_reason = "Unknown (Subject Keyword)"
|
|
600
725
|
|
|
601
726
|
return (bounce_type, bounce_reason)
|
|
727
|
+
|
|
728
|
+
def filter_pass(
|
|
729
|
+
self,
|
|
730
|
+
subject: str,
|
|
731
|
+
efrom: str,
|
|
732
|
+
eto: str,
|
|
733
|
+
ecc: str,
|
|
734
|
+
ebc: str,
|
|
735
|
+
eid: str,
|
|
736
|
+
body_plain: str,
|
|
737
|
+
body_html: str,
|
|
738
|
+
headers: dict,
|
|
739
|
+
bounce_type: Optional[str],
|
|
740
|
+
bounce_reason: Optional[str],
|
|
741
|
+
tracking_id: Optional[str],
|
|
742
|
+
) -> tuple[bool, str]:
|
|
743
|
+
"""
|
|
744
|
+
Applies filtering rules to determine if an email should be processed.
|
|
745
|
+
|
|
746
|
+
Returns:
|
|
747
|
+
True if the email should be processed, False otherwise.
|
|
748
|
+
"""
|
|
749
|
+
|
|
750
|
+
# Get filters from settings
|
|
751
|
+
filters = getattr(settings, "IMAP_EMAIL_FILTERS", None)
|
|
752
|
+
if not filters:
|
|
753
|
+
# No filters defined, allow processing
|
|
754
|
+
return (True, "No filters defined, processing all.")
|
|
755
|
+
|
|
756
|
+
# Helper function to apply regex list to a value
|
|
757
|
+
def match_any(value: str, patterns: list) -> bool:
|
|
758
|
+
for pattern in patterns:
|
|
759
|
+
if re.search(pattern, value, re.IGNORECASE):
|
|
760
|
+
return True # Match found
|
|
761
|
+
return False # No matches
|
|
762
|
+
|
|
763
|
+
# Apply filters
|
|
764
|
+
for key, patterns in filters.items():
|
|
765
|
+
if key == "SUBJECT" and patterns:
|
|
766
|
+
if not match_any(subject or "", patterns):
|
|
767
|
+
return (False, f"SUBJECT failed: {subject}")
|
|
768
|
+
|
|
769
|
+
elif key == "FROM" and patterns:
|
|
770
|
+
if not match_any(efrom or "", patterns):
|
|
771
|
+
return (False, f"FROM failed: {efrom}")
|
|
772
|
+
|
|
773
|
+
elif key == "TO" and patterns:
|
|
774
|
+
if not any(
|
|
775
|
+
match_any(targets or "", patterns)
|
|
776
|
+
for targets in (
|
|
777
|
+
eto or "",
|
|
778
|
+
ecc or "",
|
|
779
|
+
ebc or "",
|
|
780
|
+
)
|
|
781
|
+
):
|
|
782
|
+
# If no direct match, try more robust email extraction
|
|
783
|
+
# Analize only the email addresses
|
|
784
|
+
emails = re.split(r"[;,]\s*", eto or "")
|
|
785
|
+
emails += re.split(r"[;,]\s*", ecc or "")
|
|
786
|
+
emails += re.split(r"[;,]\s*", ebc or "")
|
|
787
|
+
|
|
788
|
+
# Stay only with the email and strip < and > if present
|
|
789
|
+
email_only = [
|
|
790
|
+
e.split()[-1].strip("<>") for e in emails if e
|
|
791
|
+
]
|
|
792
|
+
|
|
793
|
+
# Check if any of the emails match
|
|
794
|
+
if not any(match_any(e, patterns) for e in email_only):
|
|
795
|
+
return (False, f"TO failed: {eto}")
|
|
796
|
+
|
|
797
|
+
elif key == "MESSAGE-ID" and patterns:
|
|
798
|
+
if not match_any(eid or "", patterns):
|
|
799
|
+
return (False, f"MESSAGE-ID failed: {eid}")
|
|
800
|
+
|
|
801
|
+
elif key == "BODY_PLAIN" and patterns:
|
|
802
|
+
if not match_any(body_plain or "", patterns):
|
|
803
|
+
return (False, f"BODY_PLAIN failed: {body_plain}")
|
|
804
|
+
|
|
805
|
+
elif key == "BODY_HTML" and patterns:
|
|
806
|
+
if not match_any(body_html or "", patterns):
|
|
807
|
+
return (False, f"BODY_HTML failed: {body_html}")
|
|
808
|
+
|
|
809
|
+
elif key == "HEADER" and patterns:
|
|
810
|
+
header_matched = False
|
|
811
|
+
for header_name, header_patterns in patterns:
|
|
812
|
+
header_value = headers.get(header_name, "")
|
|
813
|
+
if match_any(header_value, header_patterns):
|
|
814
|
+
header_matched = True
|
|
815
|
+
break
|
|
816
|
+
if not header_matched:
|
|
817
|
+
return (False, f"HEADER failed: {headers}")
|
|
818
|
+
|
|
819
|
+
elif key == "BOUNCE_TYPE" and patterns:
|
|
820
|
+
if bounce_type not in patterns:
|
|
821
|
+
return (False, f"BOUNCE_TYPE failed: {bounce_type}")
|
|
822
|
+
|
|
823
|
+
elif key == "BOUNCE_REASON" and patterns:
|
|
824
|
+
if not bounce_reason or not match_any(bounce_reason, patterns):
|
|
825
|
+
return (
|
|
826
|
+
False,
|
|
827
|
+
f"BOUNCE_REASON failed: {bounce_reason}",
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
elif key == "TRACKING_ID" and patterns:
|
|
831
|
+
if patterns and not tracking_id:
|
|
832
|
+
return (False, "TRACKING_ID failed: No tracking ID")
|
|
833
|
+
|
|
834
|
+
# If all filters passed, allow processing
|
|
835
|
+
return (True, "All filters passed.")
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
class="text-nowrap">{{row.eto|codenerix}}</td>
|
|
13
13
|
<td
|
|
14
14
|
ng-class="{'info': (!row.email__pk) && (!row.bounce_type), 'warning': row.bounce_type=='S', 'danger': row.bounce_type=='H', 'text-warning': row.bounce_type=='S', 'text-danger': row.bounce_type=='H'}"
|
|
15
|
-
class="text-nowrap">
|
|
15
|
+
class="text-nowrap">
|
|
16
|
+
<span codenerix-html-compile='row.subject|codenerix:"shorttext:50"'></span>
|
|
17
|
+
</td>
|
|
16
18
|
<td
|
|
17
19
|
ng-class="{'info': (!row.email__pk) && (!row.bounce_type), 'warning': row.bounce_type=='S', 'danger': row.bounce_type=='H', 'text-warning': row.bounce_type=='S', 'text-danger': row.bounce_type=='H'}"
|
|
18
20
|
ng-click="$event.stopPropagation();"
|
{django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-codenerix-email
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.38
|
|
4
4
|
Summary: Codenerix Email is a module that enables CODENERIX to set send emails in a general manner.
|
|
5
5
|
Home-page: https://github.com/codenerix/django-codenerix-email
|
|
6
6
|
Author: Juan Miguel Taboada Godoy <juanmi@juanmitaboada.com>, Juan Soler Ruiz <soleronline@gmail.com>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
codenerix_email/__init__.py,sha256=
|
|
1
|
+
codenerix_email/__init__.py,sha256=d3ZDJ3aRhP_spoILto0bxpnTTieGJNC9i6wvMu6LSDo,149
|
|
2
2
|
codenerix_email/admin.py,sha256=w259UKFk_opGEl6PJjYHXWAHQ_8emgqmiixKT5Rid4A,1180
|
|
3
3
|
codenerix_email/apps.py,sha256=WXqu1XQibDDyCvvQYt2JbTK4GIpW8BNv5DCbRJS2mmk,149
|
|
4
4
|
codenerix_email/forms.py,sha256=38byLGxg1MOLAY1kAYChxYZj64tSgyfRvDcSbIOdV0I,5521
|
|
@@ -827,8 +827,8 @@ codenerix_email/.mypy_cache/3.10/zoneinfo/_common.data.json,sha256=e4xbNKL_yQ5h5
|
|
|
827
827
|
codenerix_email/.mypy_cache/3.10/zoneinfo/_common.meta.json,sha256=5K19XWobpSjKwiv7bZFZRcxsEfoh7b-FhYcmqB-2Iic,1737
|
|
828
828
|
codenerix_email/.mypy_cache/3.10/zoneinfo/_tzpath.data.json,sha256=CFx7Q1XfUhhuNX69prkxyirG8rfvEDCNgEHWQigKC_A,5632
|
|
829
829
|
codenerix_email/.mypy_cache/3.10/zoneinfo/_tzpath.meta.json,sha256=d1HJ_xFBI1orlZSVhH0gHWLI-dJG3zY-ZOlctOl62yU,1765
|
|
830
|
-
codenerix_email/__pycache__/__init__.cpython-310.pyc,sha256=
|
|
831
|
-
codenerix_email/__pycache__/__init__.cpython-311.pyc,sha256=
|
|
830
|
+
codenerix_email/__pycache__/__init__.cpython-310.pyc,sha256=X9LGnGfm6qTbAvEiyenE8Z40jbxj4g1kfeoRKITsWik,313
|
|
831
|
+
codenerix_email/__pycache__/__init__.cpython-311.pyc,sha256=JEmf6oZE-e3TUb2xe1Zbe_XjVsq1vfS5qIuNUfdakRc,337
|
|
832
832
|
codenerix_email/__pycache__/__init__.cpython-35.pyc,sha256=dl9lYAgrokJptUj3JAhiqTlX7d_CbncOxZeTc1USc88,308
|
|
833
833
|
codenerix_email/__pycache__/__init__.cpython-37.pyc,sha256=5d1CeFU5DrfnwrRpvSw1bHvLN9hoHXjUA3ln3rXCDo8,306
|
|
834
834
|
codenerix_email/__pycache__/__init__.cpython-39.pyc,sha256=0c6KWU_eOTlF5l9fNWv8l41b0LcfVQNUsqDvJTv2YyU,300
|
|
@@ -868,7 +868,7 @@ codenerix_email/management/__pycache__/__init__.cpython-35.pyc,sha256=sBoEWs6zdI
|
|
|
868
868
|
codenerix_email/management/__pycache__/__init__.cpython-39.pyc,sha256=uPXklfliVd3b8pLOJQT9ZeKcqmJMrGychvt68BsPulY,168
|
|
869
869
|
codenerix_email/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
870
870
|
codenerix_email/management/commands/email_test.py,sha256=SPsiq0s48sEX_G3piNHq-c1gDOH800H2zTvM19ei2LY,5605
|
|
871
|
-
codenerix_email/management/commands/emails_recv.py,sha256=
|
|
871
|
+
codenerix_email/management/commands/emails_recv.py,sha256=fDFGJZqQBGAK4jZGFITzIXZCFdMvB35nwuXmJ40XMA4,34448
|
|
872
872
|
codenerix_email/management/commands/emails_send.py,sha256=scCFklro4WVMYm-1ataSjUMsPT-Ie5u_DdA55CQcTCQ,7944
|
|
873
873
|
codenerix_email/management/commands/recv_emails.py,sha256=aXmhdXlamiNxRpMIDSKBXUBhkOcwi5l_Pme7jSQUCME,273
|
|
874
874
|
codenerix_email/management/commands/send_emails.py,sha256=a1MnpvZKAEFdXNfmI5oFUkVxy4PZ1AjaJS6GH90zeD0,273
|
|
@@ -1613,7 +1613,7 @@ codenerix_email/management/commands/.mypy_cache/3.10/zoneinfo/_tzpath.meta.json,
|
|
|
1613
1613
|
codenerix_email/management/commands/__pycache__/__init__.cpython-310.pyc,sha256=3-VfdLuaiBIg4KTIy7GETYTt2-AbfCU0vlH6fFZx7_M,189
|
|
1614
1614
|
codenerix_email/management/commands/__pycache__/__init__.cpython-311.pyc,sha256=yiqmtIhQMYXWx7g7XT-mvQNgGu_X2ymasWvVxIqPsBE,211
|
|
1615
1615
|
codenerix_email/management/commands/__pycache__/email_test.cpython-311.pyc,sha256=ql-fe6qem8jGQCu-7Wm3ZCEvzOiVMsCdy0IxOyGnJbo,5946
|
|
1616
|
-
codenerix_email/management/commands/__pycache__/emails_recv.cpython-311.pyc,sha256=
|
|
1616
|
+
codenerix_email/management/commands/__pycache__/emails_recv.cpython-311.pyc,sha256=2xdfhIh76dxEnxx7wxaDsCeycJM4wRCb14C0CJax6to,30330
|
|
1617
1617
|
codenerix_email/management/commands/__pycache__/emails_send.cpython-311.pyc,sha256=XSOhv92hH9G4Z9juLmXFTOLCS-oggZBA2TFyKIsxmd8,6868
|
|
1618
1618
|
codenerix_email/management/commands/__pycache__/recv_emails.cpython-310.pyc,sha256=qzj8puxw6pRAz_ptltybySs2mybOwdoZ8LB7Fw8YMGc,9897
|
|
1619
1619
|
codenerix_email/management/commands/__pycache__/recv_emails.cpython-311.pyc,sha256=YJoyWZ8Ax_ej7u9_YKjtru8BN8bKlMuvqNiTsLoWYUw,643
|
|
@@ -1686,9 +1686,9 @@ codenerix_email/migrations/__pycache__/__init__.cpython-311.pyc,sha256=RbbUUEhcJ
|
|
|
1686
1686
|
codenerix_email/migrations/__pycache__/__init__.cpython-35.pyc,sha256=2g70xiMW6oJNkIpRM-0Dr5h7AUac-3xyCXPONxp9BBw,147
|
|
1687
1687
|
codenerix_email/migrations/__pycache__/__init__.cpython-39.pyc,sha256=qNj2NH0YvoWPnCKxkVZPsEFsbM05y7t1njMskNISdVQ,168
|
|
1688
1688
|
codenerix_email/static/codenerix_email/emailmessages_rows.html,sha256=NyZpKPSHAAIywJX2ncS0H2bkqOVtMUwAdbYmkC4dKmk,2202
|
|
1689
|
-
codenerix_email/static/codenerix_email/emailreceiveds_rows.html,sha256=
|
|
1690
|
-
django_codenerix_email-4.0.
|
|
1691
|
-
django_codenerix_email-4.0.
|
|
1692
|
-
django_codenerix_email-4.0.
|
|
1693
|
-
django_codenerix_email-4.0.
|
|
1694
|
-
django_codenerix_email-4.0.
|
|
1689
|
+
codenerix_email/static/codenerix_email/emailreceiveds_rows.html,sha256=u9DXVdzKhx9WlJgcK_cT2DfGp9bGIKTBn3LDQplB4g4,2032
|
|
1690
|
+
django_codenerix_email-4.0.38.dist-info/LICENSE,sha256=IXMIpi75XsrJt1Sznt4EftT9c_4X0C9eqK4tHhH8H48,11339
|
|
1691
|
+
django_codenerix_email-4.0.38.dist-info/METADATA,sha256=a7ZWYCckl3ouPLkC7uN1-LuUTN4Qxm0tlKiQHPSTRZY,2676
|
|
1692
|
+
django_codenerix_email-4.0.38.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
|
|
1693
|
+
django_codenerix_email-4.0.38.dist-info/top_level.txt,sha256=lljSA0iKE_UBEM5gIrGQwioC_i8Jjnp-aR1LFElENgw,16
|
|
1694
|
+
django_codenerix_email-4.0.38.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{django_codenerix_email-4.0.37.dist-info → django_codenerix_email-4.0.38.dist-info}/top_level.txt
RENAMED
|
File without changes
|