1
0
Fork 1
mirror of https://github.com/coddingtonbear/django-mailbox.git synced 2026-07-09 22:38:19 +02:00

Merge pull request #2 from sunset-crew/release_v0.1.1

Release v0.1.1
This commit is contained in:
Joe 2021-02-03 23:08:31 -05:00 committed by GitHub
commit 1f018e9bdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 2443 additions and 1555 deletions

View file

@ -1,7 +0,0 @@
[bumpversion]
current_version = 4.8.2
commit = True
tag = True
tag_name = {new_version}
[bumpversion:file:django_mailbox/__init__.py]

View file

@ -1,2 +1,4 @@
[flake8]
exclude = django_mailbox/migrations, django_mailbox/south_migrations
max-line-length = 200
exclude = docs, django_mailbox/migrations, django_mailbox/south_migrations
ignore = E231,W503

1
.gitignore vendored
View file

@ -16,3 +16,4 @@ messages
manage.py
old/
poetry.lock
websrv

View file

@ -1,46 +0,0 @@
version: ~> 1.0
os: linux
language: python
jobs:
- env: TOX_ENV=docs
python: 3.8
# sort by django version, next to by python version
# Django 1.11 support all supported Python interpreter
- env: TOX_ENV=django111-py35
python: 3.5
- env: TOX_ENV=django111-py36
python: 3.6
# Django 2.0 support 3.5, 3.6
- env: TOX_ENV=django20-py35
python: 3.5
- env: TOX_ENV=django20-py36
python: 3.6
# Django 2.1 support Python 3.5, 3.6, 3.7
- env: TOX_ENV=django21-py35
python: 3.5
- env: TOX_ENV=django21-py36
python: 3.6
- env: TOX_ENV=django21-py37
python: 3.7
# Django 2.2 support Python 3.5, 3.6, 3.7
- env: TOX_ENV=django22-py35
python: 3.5
- env: TOX_ENV=django22-py36
python: 3.6
- env: TOX_ENV=django22-py37
python: 3.7
# Django 3.0 (beta) support Python 3.6, 3.7, 3.8
- env: TOX_ENV=django30-py36
python: 3.6
- env: TOX_ENV=django30-py37
python: 3.7
- env: TOX_ENV=django30-py38 INTEGRATION=1
python: 3.8
install:
- pip install tox
script:
- tox -e $TOX_ENV

View file

@ -5,10 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
[Also based on](https://github.com/conventional-changelog/standard-version/blob/master/CHANGELOG.md) so decending.
## [0.1.1] - 2021-02-03
### Added
- adds modified documenation
- adds testable repo with added features
## [0.1.0] - 2021-02-03
### Added
- bot - adds changelog
### Changed
- changes repo to customized solution

View file

@ -1,9 +0,0 @@
include *.rst
include .travis.yml
include MANIFEST
recursive-include django_mailbox *.eml
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs Makefile
recursive-include django_mailbox/locale *.po
recursive-include django_mailbox/locale *.mo

View file

@ -1,3 +1,3 @@
__version__ = '4.8.2'
__version__ = "4.8.2"
default_app_config = 'django_mailbox.apps.MailBoxConfig'
default_app_config = "django_mailbox.apps.MailBoxConfig"

View file

@ -23,35 +23,38 @@ def get_new_mail(mailbox_admin, request, queryset):
queryset.get_new_mail()
get_new_mail.short_description = _('Get new mail')
get_new_mail.short_description = _("Get new mail")
def resend_message_received_signal(message_admin, request, queryset):
for message in queryset.all():
logger.debug('Resending \'message_received\' signal for %s' % message)
logger.debug("Resending 'message_received' signal for %s" % message)
message_received.send(sender=message_admin, message=message)
resend_message_received_signal.short_description = (
_('Re-send message received signal')
)
resend_message_received_signal.short_description = _("Re-send message received signal")
class MailboxAdmin(admin.ModelAdmin):
list_display = (
'name',
'uri',
'from_email',
'active',
'last_polling',
"name",
"uri",
"from_email",
"active",
"last_polling",
)
readonly_fields = ['last_polling', ]
readonly_fields = [
"last_polling",
]
actions = [get_new_mail]
class MessageAttachmentAdmin(admin.ModelAdmin):
raw_id_fields = ('message', )
list_display = ('message', 'document',)
raw_id_fields = ("message",)
list_display = (
"message",
"document",
)
class MessageAttachmentInline(admin.TabularInline):
@ -63,50 +66,44 @@ class MessageAdmin(admin.ModelAdmin):
def attachment_count(self, msg):
return msg.attachments.count()
attachment_count.short_description = _('Attachment count')
attachment_count.short_description = _("Attachment count")
def subject(self, msg):
return convert_header_to_unicode(msg.subject)
def envelope_headers(self, msg):
email = msg.get_email_object()
return '\n'.join(
[('{}: {}'.format(h, v)) for h, v in email.items()]
)
return "\n".join([("{}: {}".format(h, v)) for h, v in email.items()])
inlines = [
MessageAttachmentInline,
]
list_display = (
'subject',
'processed',
'read',
'mailbox',
'outgoing',
'attachment_count',
"subject",
"processed",
"read",
"mailbox",
"outgoing",
"attachment_count",
)
ordering = ['-processed']
ordering = ["-processed"]
list_filter = (
'mailbox',
'outgoing',
'processed',
'read',
)
exclude = (
'body',
)
raw_id_fields = (
'in_reply_to',
"mailbox",
"outgoing",
"processed",
"read",
)
exclude = ("body",)
raw_id_fields = ("in_reply_to",)
readonly_fields = (
'envelope_headers',
'text',
'html',
"envelope_headers",
"text",
"html",
)
actions = [resend_message_received_signal]
if getattr(settings, 'DJANGO_MAILBOX_ADMIN_ENABLED', True):
if getattr(settings, "DJANGO_MAILBOX_ADMIN_ENABLED", True):
admin.site.register(Message, MessageAdmin)
admin.site.register(MessageAttachment, MessageAttachmentAdmin)
admin.site.register(Mailbox, MailboxAdmin)

View file

@ -3,5 +3,5 @@ from django.utils.translation import gettext_lazy as _
class MailBoxConfig(AppConfig):
name = 'django_mailbox'
name = "django_mailbox"
verbose_name = _("Mail Box")

View file

@ -28,7 +28,7 @@ def get_google_access_token(email):
# TODO: This should be cacheable
try:
me = UserSocialAuth.objects.get(uid=email, provider="google-oauth2")
return me.extra_data['access_token']
return me.extra_data["access_token"]
except (UserSocialAuth.DoesNotExist, KeyError):
raise AccessTokenNotFound
@ -45,7 +45,7 @@ def update_google_extra_data(email, extra_data):
def get_google_refresh_token(email):
try:
me = UserSocialAuth.objects.get(uid=email, provider="google-oauth2")
return me.extra_data['refresh_token']
return me.extra_data["refresh_token"]
except (UserSocialAuth.DoesNotExist, KeyError):
raise RefreshTokenNotFound
@ -72,9 +72,11 @@ def google_api_post(email, url, post_data, authorized=True):
# TODO: Make this a lot less ugly. especially the 401 handling
headers = dict()
if authorized is True:
headers.update(dict(
headers.update(
dict(
Authorization="Bearer %s" % get_google_access_token(email),
))
)
)
r = requests.post(url, headers=headers, data=post_data)
if r.status_code == 401:
refresh_authorization(email)
@ -92,20 +94,20 @@ def refresh_authorization(email):
refresh_token=refresh_token,
client_id=get_google_consumer_key(),
client_secret=get_google_consumer_secret(),
grant_type='refresh_token',
grant_type="refresh_token",
)
results = google_api_post(
email,
"https://accounts.google.com/o/oauth2/token?access_type=offline",
post_data,
authorized=False)
results.update({'refresh_token': refresh_token})
authorized=False,
)
results.update({"refresh_token": refresh_token})
update_google_extra_data(email, results)
def fetch_user_info(email):
result = google_api_get(
email,
"https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
email, "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
)
return result

View file

@ -13,18 +13,11 @@ class Command(BaseCommand):
def handle(self, *args, **options):
mailboxes = Mailbox.active_mailboxes.all()
if args:
mailboxes = mailboxes.filter(
name=' '.join(args)
)
mailboxes = mailboxes.filter(name=" ".join(args))
for mailbox in mailboxes:
logger.info(
'Gathering messages for %s',
mailbox.name
)
logger.info("Gathering messages for %s", mailbox.name)
messages = mailbox.get_new_mail()
for message in messages:
logger.info(
'Received %s (from %s)',
message.subject,
message.from_address
"Received %s (from %s)", message.subject, message.from_address
)

View file

@ -1,6 +1,7 @@
import email
import logging
import sys
try:
from email import utils
except ImportError:
@ -21,9 +22,9 @@ class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
'mailbox_name',
nargs='?',
help="The name of the mailbox that will receive the message"
"mailbox_name",
nargs="?",
help="The name of the mailbox that will receive the message",
)
def handle(self, mailbox_name=None, *args, **options):
@ -34,10 +35,7 @@ class Command(BaseCommand):
else:
mailbox = self.get_mailbox_for_message(message)
mailbox.process_incoming_message(message)
logger.info(
"Message received from %s",
message['from']
)
logger.info("Message received from %s", message["from"])
else:
logger.warning("Message not processable.")
@ -48,5 +46,5 @@ class Command(BaseCommand):
return mailbox
def get_mailbox_for_message(self, message):
email_address = utils.parseaddr(message['to'])[1][0:255]
email_address = utils.parseaddr(message["to"])[1][0:255]
return self.get_mailbox_by_name(email_address)

View file

@ -22,14 +22,13 @@ class Command(BaseCommand):
have been quite unlucky to have ran the bad migration).
"""
def handle(self, *args, **options):
attachment_hash_map = {}
attachments_without_messages = MessageAttachment.objects.filter(
message=None
).order_by(
'id'
)
).order_by("id")
if attachments_without_messages.count() < 1:
return
@ -40,13 +39,13 @@ class Command(BaseCommand):
md5.update(chunk)
attachment_hash_map[md5.hexdigest()] = attachment.pk
for message_record in Message.objects.all().order_by('id'):
for message_record in Message.objects.all().order_by("id"):
message = email.message_from_string(message_record.body)
if message.is_multipart():
for part in message.walk():
if part.get_content_maintype() == 'multipart':
if part.get_content_maintype() == "multipart":
continue
if part.get('Content-Disposition') is None:
if part.get("Content-Disposition") is None:
continue
md5 = hashlib.md5()
md5.update(part.get_payload(decode=True))
@ -61,11 +60,11 @@ class Command(BaseCommand):
"Associated message %s with attachment %s (%s)",
message_record.pk,
attachment.pk,
digest
digest,
)
else:
logger.info(
"%s(%s) not found in currently-stored attachments",
part.get_filename(),
digest
digest,
)

View file

@ -3,54 +3,163 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Mailbox',
name="Mailbox",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=255, verbose_name='Name')),
('uri', models.CharField(default=None, max_length=255, blank=True, help_text="Example: imap+ssl://myusername:mypassword@someserver <br /><br />Internet transports include 'imap' and 'pop3'; common local file transports include 'maildir', 'mbox', and less commonly 'babyl', 'mh', and 'mmdf'. <br /><br />Be sure to urlencode your username and password should they contain illegal characters (like @, :, etc).", null=True, verbose_name='URI')),
('from_email', models.CharField(default=None, max_length=255, blank=True, help_text="Example: MailBot &lt;mailbot@yourdomain.com&gt;<br />'From' header to set for outgoing email.<br /><br />If you do not use this e-mail inbox for outgoing mail, this setting is unnecessary.<br />If you send e-mail without setting this, your 'From' header will'be set to match the setting `DEFAULT_FROM_EMAIL`.", null=True, verbose_name='From email')),
('active', models.BooleanField(default=True, help_text='Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ', verbose_name='Active')),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("name", models.CharField(max_length=255, verbose_name="Name")),
(
"uri",
models.CharField(
default=None,
max_length=255,
blank=True,
help_text="Example: imap+ssl://myusername:mypassword@someserver <br /><br />Internet transports include 'imap' and 'pop3'; common local file transports include 'maildir', 'mbox', and less commonly 'babyl', 'mh', and 'mmdf'. <br /><br />Be sure to urlencode your username and password should they contain illegal characters (like @, :, etc).",
null=True,
verbose_name="URI",
),
),
(
"from_email",
models.CharField(
default=None,
max_length=255,
blank=True,
help_text="Example: MailBot &lt;mailbot@yourdomain.com&gt;<br />'From' header to set for outgoing email.<br /><br />If you do not use this e-mail inbox for outgoing mail, this setting is unnecessary.<br />If you send e-mail without setting this, your 'From' header will'be set to match the setting `DEFAULT_FROM_EMAIL`.",
null=True,
verbose_name="From email",
),
),
(
"active",
models.BooleanField(
default=True,
help_text="Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ",
verbose_name="Active",
),
),
],
options={
'verbose_name_plural': 'Mailboxes',
"verbose_name_plural": "Mailboxes",
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Message',
name="Message",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('subject', models.CharField(max_length=255, verbose_name='Subject')),
('message_id', models.CharField(max_length=255, verbose_name='Message ID')),
('from_header', models.CharField(max_length=255, verbose_name='From header')),
('to_header', models.TextField(verbose_name='To header')),
('outgoing', models.BooleanField(default=False, verbose_name='Outgoing')),
('body', models.TextField(verbose_name='Body')),
('encoded', models.BooleanField(default=False, help_text='True if the e-mail body is Base64 encoded', verbose_name='Encoded')),
('processed', models.DateTimeField(auto_now_add=True, verbose_name='Processed')),
('read', models.DateTimeField(default=None, null=True, verbose_name='Read', blank=True)),
('in_reply_to', models.ForeignKey(related_name='replies', verbose_name='In reply to', blank=True, to='django_mailbox.Message', null=True, on_delete=models.CASCADE)),
('mailbox', models.ForeignKey(related_name='messages', verbose_name='Mailbox', to='django_mailbox.Mailbox', on_delete=models.CASCADE)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
("subject", models.CharField(max_length=255, verbose_name="Subject")),
(
"message_id",
models.CharField(max_length=255, verbose_name="Message ID"),
),
(
"from_header",
models.CharField(max_length=255, verbose_name="From header"),
),
("to_header", models.TextField(verbose_name="To header")),
(
"outgoing",
models.BooleanField(default=False, verbose_name="Outgoing"),
),
("body", models.TextField(verbose_name="Body")),
(
"encoded",
models.BooleanField(
default=False,
help_text="True if the e-mail body is Base64 encoded",
verbose_name="Encoded",
),
),
(
"processed",
models.DateTimeField(auto_now_add=True, verbose_name="Processed"),
),
(
"read",
models.DateTimeField(
default=None, null=True, verbose_name="Read", blank=True
),
),
(
"in_reply_to",
models.ForeignKey(
related_name="replies",
verbose_name="In reply to",
blank=True,
to="django_mailbox.Message",
null=True,
on_delete=models.CASCADE,
),
),
(
"mailbox",
models.ForeignKey(
related_name="messages",
verbose_name="Mailbox",
to="django_mailbox.Mailbox",
on_delete=models.CASCADE,
),
),
],
options={
},
options={},
bases=(models.Model,),
),
migrations.CreateModel(
name='MessageAttachment',
name="MessageAttachment",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('headers', models.TextField(null=True, verbose_name='Headers', blank=True)),
('document', models.FileField(upload_to=b'mailbox_attachments/%Y/%m/%d/', verbose_name='Document')),
('message', models.ForeignKey(related_name='attachments', verbose_name='Message', blank=True, to='django_mailbox.Message', null=True, on_delete=models.CASCADE)),
(
"id",
models.AutoField(
verbose_name="ID",
serialize=False,
auto_created=True,
primary_key=True,
),
),
(
"headers",
models.TextField(null=True, verbose_name="Headers", blank=True),
),
(
"document",
models.FileField(
upload_to=b"mailbox_attachments/%Y/%m/%d/",
verbose_name="Document",
),
),
(
"message",
models.ForeignKey(
related_name="attachments",
verbose_name="Message",
blank=True,
to="django_mailbox.Message",
null=True,
on_delete=models.CASCADE,
),
),
],
options={
},
options={},
bases=(models.Model,),
),
]

View file

@ -4,14 +4,19 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0001_initial'),
("django_mailbox", "0001_initial"),
]
operations = [
migrations.AddField(
model_name='message',
name='eml',
field=models.FileField(help_text='Original full content of message', upload_to=b'messages', null=True, verbose_name='Message as a file'),
model_name="message",
name="eml",
field=models.FileField(
help_text="Original full content of message",
upload_to=b"messages",
null=True,
verbose_name="Message as a file",
),
preserve_default=True,
),
]

View file

@ -4,13 +4,18 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0002_add_eml_to_message'),
("django_mailbox", "0002_add_eml_to_message"),
]
operations = [
migrations.AlterField(
model_name='message',
name='eml',
field=models.FileField(help_text='Original full content of message', upload_to=b'messages', null=True, verbose_name='Raw message contents'),
model_name="message",
name="eml",
field=models.FileField(
help_text="Original full content of message",
upload_to=b"messages",
null=True,
verbose_name="Raw message contents",
),
),
]

View file

@ -4,18 +4,25 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0003_auto_20150409_0316'),
("django_mailbox", "0003_auto_20150409_0316"),
]
operations = [
migrations.AlterField(
model_name='message',
name='eml',
field=models.FileField(verbose_name='Raw message contents', upload_to='messages', null=True, help_text='Original full content of message'),
model_name="message",
name="eml",
field=models.FileField(
verbose_name="Raw message contents",
upload_to="messages",
null=True,
help_text="Original full content of message",
),
),
migrations.AlterField(
model_name='messageattachment',
name='document',
field=models.FileField(verbose_name='Document', upload_to='mailbox_attachments/%Y/%m/%d/'),
model_name="messageattachment",
name="document",
field=models.FileField(
verbose_name="Document", upload_to="mailbox_attachments/%Y/%m/%d/"
),
),
]

View file

@ -5,13 +5,16 @@ import django_mailbox.utils
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0004_bytestring_to_unicode'),
("django_mailbox", "0004_bytestring_to_unicode"),
]
operations = [
migrations.AlterField(
model_name='messageattachment',
name='document',
field=models.FileField(upload_to=django_mailbox.utils.get_attachment_save_path, verbose_name='Document'),
model_name="messageattachment",
name="document",
field=models.FileField(
upload_to=django_mailbox.utils.get_attachment_save_path,
verbose_name="Document",
),
),
]

View file

@ -6,13 +6,18 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0005_auto_20160523_2240'),
("django_mailbox", "0005_auto_20160523_2240"),
]
operations = [
migrations.AddField(
model_name='mailbox',
name='last_polling',
field=models.DateTimeField(blank=True, help_text='The time of last successful polling for messages.It is blank for new mailboxes and is not set for mailboxes that only receive messages via a pipe.', null=True, verbose_name='Last polling'),
model_name="mailbox",
name="last_polling",
field=models.DateTimeField(
blank=True,
help_text="The time of last successful polling for messages.It is blank for new mailboxes and is not set for mailboxes that only receive messages via a pipe.",
null=True,
verbose_name="Last polling",
),
),
]

View file

@ -6,20 +6,26 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0006_mailbox_last_polling'),
("django_mailbox", "0006_mailbox_last_polling"),
]
operations = [
migrations.AlterModelOptions(
name='mailbox',
options={'verbose_name': 'Mailbox', 'verbose_name_plural': 'Mailboxes'},
name="mailbox",
options={"verbose_name": "Mailbox", "verbose_name_plural": "Mailboxes"},
),
migrations.AlterModelOptions(
name='message',
options={'verbose_name': 'E-mail message', 'verbose_name_plural': 'E-mail messages'},
name="message",
options={
"verbose_name": "E-mail message",
"verbose_name_plural": "E-mail messages",
},
),
migrations.AlterModelOptions(
name='messageattachment',
options={'verbose_name': 'Message attachment', 'verbose_name_plural': 'Message attachments'},
name="messageattachment",
options={
"verbose_name": "Message attachment",
"verbose_name_plural": "Message attachments",
},
),
]

View file

@ -6,18 +6,25 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_mailbox', '0007_auto_20180421_0026'),
("django_mailbox", "0007_auto_20180421_0026"),
]
operations = [
migrations.AlterField(
model_name='mailbox',
name='active',
field=models.BooleanField(blank=True, default=True, help_text='Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ', verbose_name='Active'),
model_name="mailbox",
name="active",
field=models.BooleanField(
blank=True,
default=True,
help_text="Check this e-mail inbox for new e-mail messages during polling cycles. This checkbox does not have an effect upon whether mail is collected here when this mailbox receives mail from a pipe, and does not affect whether e-mail messages can be dispatched from this mailbox. ",
verbose_name="Active",
),
),
migrations.AlterField(
model_name='message',
name='outgoing',
field=models.BooleanField(blank=True, default=False, verbose_name='Outgoing'),
model_name="message",
name="outgoing",
field=models.BooleanField(
blank=True, default=False, verbose_name="Outgoing"
),
),
]

View file

@ -15,7 +15,8 @@ import email
import logging
import mimetypes
import os.path
import sys
# import sys
import uuid
from tempfile import NamedTemporaryFile
@ -29,9 +30,16 @@ from django.utils.timezone import now
from django_mailbox import utils
from django_mailbox.signals import message_received
from django_mailbox.transports import Pop3Transport, ImapTransport, \
MaildirTransport, MboxTransport, BabylTransport, MHTransport, \
MMDFTransport, GmailImapTransport
from django_mailbox.transports import (
Pop3Transport,
ImapTransport,
MaildirTransport,
MboxTransport,
BabylTransport,
MHTransport,
MMDFTransport,
GmailImapTransport,
)
logger = logging.getLogger(__name__)
@ -40,9 +48,9 @@ class MailboxQuerySet(models.QuerySet):
def get_new_mail(self):
count = 0
for mailbox in self.all():
logger.debug('Receiving mail for %s' % mailbox)
logger.debug("Receiving mail for %s" % mailbox)
count += sum(1 for i in mailbox.get_new_mail())
logger.debug('Received %d %s.', count, 'mails' if count != 1 else 'mail')
logger.debug("Received %d %s.", count, "mails" if count != 1 else "mail")
class MailboxManager(models.Manager):
@ -52,21 +60,26 @@ class MailboxManager(models.Manager):
class ActiveMailboxManager(MailboxManager):
def get_queryset(self):
return super().get_queryset().filter(
return (
super()
.get_queryset()
.filter(
active=True,
)
)
class Mailbox(models.Model):
name = models.CharField(
_('Name'),
_("Name"),
max_length=255,
)
uri = models.CharField(
_('URI'),
_("URI"),
max_length=255,
help_text=(_(
help_text=(
_(
"Example: imap+ssl://myusername:mypassword@someserver <br />"
"<br />"
"Internet transports include 'imap' and 'pop3'; "
@ -75,16 +88,18 @@ class Mailbox(models.Model):
"<br />"
"Be sure to urlencode your username and password should they "
"contain illegal characters (like @, :, etc)."
)),
)
),
blank=True,
null=True,
default=None,
)
from_email = models.CharField(
_('From email'),
_("From email"),
max_length=255,
help_text=(_(
help_text=(
_(
"Example: MailBot &lt;mailbot@yourdomain.com&gt;<br />"
"'From' header to set for outgoing email.<br />"
"<br />"
@ -92,32 +107,39 @@ class Mailbox(models.Model):
"setting is unnecessary.<br />"
"If you send e-mail without setting this, your 'From' header will'"
"be set to match the setting `DEFAULT_FROM_EMAIL`."
)),
)
),
blank=True,
null=True,
default=None,
)
active = models.BooleanField(
_('Active'),
help_text=(_(
_("Active"),
help_text=(
_(
"Check this e-mail inbox for new e-mail messages during polling "
"cycles. This checkbox does not have an effect upon whether "
"mail is collected here when this mailbox receives mail from a "
"pipe, and does not affect whether e-mail messages can be "
"dispatched from this mailbox. "
)),
)
),
blank=True,
default=True,
)
last_polling = models.DateTimeField(
_("Last polling"),
help_text=(_("The time of last successful polling for messages."
help_text=(
_(
"The time of last successful polling for messages."
"It is blank for new mailboxes and is not set for "
"mailboxes that only receive messages via a pipe.")),
"mailboxes that only receive messages via a pipe."
)
),
blank=True,
null=True
null=True,
)
objects = MailboxManager()
@ -153,30 +175,30 @@ class Mailbox(models.Model):
@property
def location(self):
"""Returns the location (domain and path) of messages."""
return self._domain if self._domain else '' + self._protocol_info.path
return self._domain if self._domain else "" + self._protocol_info.path
@property
def type(self):
"""Returns the 'transport' name for this mailbox."""
scheme = self._protocol_info.scheme.lower()
if '+' in scheme:
return scheme.split('+')[0]
if "+" in scheme:
return scheme.split("+")[0]
return scheme
@property
def use_ssl(self):
"""Returns whether or not this mailbox's connection uses SSL."""
return '+ssl' in self._protocol_info.scheme.lower()
return "+ssl" in self._protocol_info.scheme.lower()
@property
def use_tls(self):
"""Returns whether or not this mailbox's connection uses STARTTLS."""
return '+tls' in self._protocol_info.scheme.lower()
return "+tls" in self._protocol_info.scheme.lower()
@property
def archive(self):
"""Returns (if specified) the folder to archive messages to."""
archive_folder = self._query_string.get('archive', None)
archive_folder = self._query_string.get("archive", None)
if not archive_folder:
return None
return archive_folder[0]
@ -184,7 +206,7 @@ class Mailbox(models.Model):
@property
def folder(self):
"""Returns (if specified) the folder to fetch mail from."""
folder = self._query_string.get('folder', None)
folder = self._query_string.get("folder", None)
if not folder:
return None
return folder[0]
@ -198,40 +220,38 @@ class Mailbox(models.Model):
"""
if not self.uri:
return None
elif self.type == 'imap':
elif self.type == "imap":
conn = ImapTransport(
self.location,
port=self.port if self.port else None,
ssl=self.use_ssl,
tls=self.use_tls,
archive=self.archive,
folder=self.folder
folder=self.folder,
)
conn.connect(self.username, self.password)
elif self.type == 'gmail':
elif self.type == "gmail":
conn = GmailImapTransport(
self.location,
port=self.port if self.port else None,
ssl=True,
archive=self.archive
archive=self.archive,
)
conn.connect(self.username, self.password)
elif self.type == 'pop3':
elif self.type == "pop3":
conn = Pop3Transport(
self.location,
port=self.port if self.port else None,
ssl=self.use_ssl
self.location, port=self.port if self.port else None, ssl=self.use_ssl
)
conn.connect(self.username, self.password)
elif self.type == 'maildir':
elif self.type == "maildir":
conn = MaildirTransport(self.location)
elif self.type == 'mbox':
elif self.type == "mbox":
conn = MboxTransport(self.location)
elif self.type == 'babyl':
elif self.type == "babyl":
conn = BabylTransport(self.location)
elif self.type == 'mh':
elif self.type == "mh":
conn = MHTransport(self.location)
elif self.type == 'mmdf':
elif self.type == "mmdf":
conn = MMDFTransport(self.location)
return conn
@ -264,29 +284,22 @@ class Mailbox(models.Model):
for header, value in msg.items():
new[header] = value
for part in msg.get_payload():
new.attach(
self._get_dehydrated_message(part, record)
)
new.attach(self._get_dehydrated_message(part, record))
elif (
settings['strip_unallowed_mimetypes']
and not msg.get_content_type() in settings['allowed_mimetypes']
settings["strip_unallowed_mimetypes"]
and not msg.get_content_type() in settings["allowed_mimetypes"]
):
for header, value in msg.items():
new[header] = value
# Delete header, otherwise when attempting to deserialize the
# payload, it will be expecting a body for this.
del new['Content-Transfer-Encoding']
new[settings['altered_message_header']] = (
'Stripped; Content type %s not allowed' % (
msg.get_content_type()
)
)
new.set_payload('')
elif (
(
msg.get_content_type() not in settings['text_stored_mimetypes']
) or
('attachment' in msg.get('Content-Disposition', ''))
del new["Content-Transfer-Encoding"]
new[
settings["altered_message_header"]
] = "Stripped; Content type %s not allowed" % (msg.get_content_type())
new.set_payload("")
elif (msg.get_content_type() not in settings["text_stored_mimetypes"]) or (
"attachment" in msg.get("Content-Disposition", "")
):
filename = None
raw_filename = msg.get_filename()
@ -297,17 +310,13 @@ class Mailbox(models.Model):
else:
_, extension = os.path.splitext(filename)
if not extension:
extension = '.bin'
extension = ".bin"
attachment = MessageAttachment()
attachment.document.save(
uuid.uuid4().hex + extension,
ContentFile(
BytesIO(
msg.get_payload(decode=True)
).getvalue()
)
ContentFile(BytesIO(msg.get_payload(decode=True)).getvalue()),
)
attachment.message = record
for key, value in msg.items():
@ -315,14 +324,14 @@ class Mailbox(models.Model):
attachment.save()
placeholder = EmailMessage()
placeholder[
settings['attachment_interpolation_header']
] = str(attachment.pk)
placeholder[settings["attachment_interpolation_header"]] = str(
attachment.pk
)
new = placeholder
else:
content_charset = msg.get_content_charset()
if not content_charset:
content_charset = 'ascii'
content_charset = "ascii"
try:
# Make sure that the payload can be properly decoded in the
# defined charset, if it can't, let's mash some things
@ -330,26 +339,15 @@ class Mailbox(models.Model):
msg.get_payload(decode=True).decode(content_charset)
except LookupError:
logger.warning(
"Unknown encoding %s; interpreting as ASCII!",
content_charset
)
msg.set_payload(
msg.get_payload(decode=True).decode(
'ascii',
'ignore'
)
"Unknown encoding %s; interpreting as ASCII!", content_charset
)
msg.set_payload(msg.get_payload(decode=True).decode("ascii", "ignore"))
except ValueError:
logger.warning(
"Decoding error encountered; interpreting %s as ASCII!",
content_charset
)
msg.set_payload(
msg.get_payload(decode=True).decode(
'ascii',
'ignore'
)
content_charset,
)
msg.set_payload(msg.get_payload(decode=True).decode("ascii", "ignore"))
new = msg
return new
@ -358,23 +356,19 @@ class Mailbox(models.Model):
msg._email_object = message
settings = utils.get_settings()
if settings['store_original_message']:
if settings["store_original_message"]:
self._process_save_original_message(message, msg)
msg.mailbox = self
if 'subject' in message:
msg.subject = (
utils.convert_header_to_unicode(message['subject'])[0:255]
)
if 'message-id' in message:
msg.message_id = message['message-id'][0:255].strip()
if 'from' in message:
msg.from_header = utils.convert_header_to_unicode(message['from'])
if 'to' in message:
msg.to_header = utils.convert_header_to_unicode(message['to'])
elif 'Delivered-To' in message:
msg.to_header = utils.convert_header_to_unicode(
message['Delivered-To']
)
if "subject" in message:
msg.subject = utils.convert_header_to_unicode(message["subject"])[0:255]
if "message-id" in message:
msg.message_id = message["message-id"][0:255].strip()
if "from" in message:
msg.from_header = utils.convert_header_to_unicode(message["from"])
if "to" in message:
msg.to_header = utils.convert_header_to_unicode(message["to"])
elif "Delivered-To" in message:
msg.to_header = utils.convert_header_to_unicode(message["Delivered-To"])
msg.save()
message = self._get_dehydrated_message(message, msg)
try:
@ -382,13 +376,16 @@ class Mailbox(models.Model):
except KeyError as exc:
# email.message.replace_header may raise 'KeyError' if the header
# 'content-transfer-encoding' is missing
logger.warning("Failed to parse message: %s", exc,)
logger.warning(
"Failed to parse message: %s",
exc,
)
return None
msg.set_body(body)
if message['in-reply-to']:
if message["in-reply-to"]:
try:
msg.in_reply_to = Message.objects.filter(
message_id=message['in-reply-to'].strip()
message_id=message["in-reply-to"].strip()
)[0]
except IndexError:
pass
@ -397,36 +394,31 @@ class Mailbox(models.Model):
def _process_save_original_message(self, message, msg):
settings = utils.get_settings()
if settings['compress_original_message']:
if settings["compress_original_message"]:
with NamedTemporaryFile(suffix=".eml.gz") as fp_tmp:
with gzip.GzipFile(fileobj=fp_tmp, mode="w") as fp:
fp.write(message.as_string().encode('utf-8'))
msg.eml.save(
"{}.eml.gz".format(uuid.uuid4()),
File(fp_tmp),
save=False
)
fp.write(message.as_string().encode("utf-8"))
msg.eml.save("{}.eml.gz".format(uuid.uuid4()), File(fp_tmp), save=False)
else:
msg.eml.save(
'%s.eml' % uuid.uuid4(),
ContentFile(message.as_string()),
save=False
"%s.eml" % uuid.uuid4(), ContentFile(message.as_string()), save=False
)
def get_new_mail(self, condition=None):
"""Connect to this transport and fetch new messages."""
new_mail = []
# Delete this
# new_mail = []
connection = self.get_connection()
if not connection:
return
for message in connection.get_message(condition):
msg = self.process_incoming_message(message)
if not msg is None:
if msg is not None:
yield msg
self.last_polling = now()
if django.VERSION >= (1, 5): # Django 1.5 introduces update_fields
self.save(update_fields=['last_polling'])
self.save(update_fields=["last_polling"])
else:
self.save()
@ -434,100 +426,97 @@ class Mailbox(models.Model):
return self.name
class Meta:
verbose_name = _('Mailbox')
verbose_name_plural = _('Mailboxes')
verbose_name = _("Mailbox")
verbose_name_plural = _("Mailboxes")
class IncomingMessageManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(
return (
super()
.get_queryset()
.filter(
outgoing=False,
)
)
class OutgoingMessageManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(
return (
super()
.get_queryset()
.filter(
outgoing=True,
)
)
class UnreadMessageManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(
read=None
)
return super().get_queryset().filter(read=None)
class Message(models.Model):
mailbox = models.ForeignKey(
Mailbox,
related_name='messages',
verbose_name=_('Mailbox'),
on_delete=models.CASCADE
related_name="messages",
verbose_name=_("Mailbox"),
on_delete=models.CASCADE,
)
subject = models.CharField(
_('Subject'),
max_length=255
)
subject = models.CharField(_("Subject"), max_length=255)
message_id = models.CharField(
_('Message ID'),
max_length=255
)
message_id = models.CharField(_("Message ID"), max_length=255)
in_reply_to = models.ForeignKey(
'django_mailbox.Message',
related_name='replies',
"django_mailbox.Message",
related_name="replies",
blank=True,
null=True,
verbose_name=_('In reply to'),
on_delete=models.CASCADE
verbose_name=_("In reply to"),
on_delete=models.CASCADE,
)
from_header = models.CharField(
_('From header'),
_("From header"),
max_length=255,
)
to_header = models.TextField(
_('To header'),
_("To header"),
)
outgoing = models.BooleanField(
_('Outgoing'),
_("Outgoing"),
default=False,
blank=True,
)
body = models.TextField(
_('Body'),
_("Body"),
)
encoded = models.BooleanField(
_('Encoded'),
_("Encoded"),
default=False,
help_text=_('True if the e-mail body is Base64 encoded'),
help_text=_("True if the e-mail body is Base64 encoded"),
)
processed = models.DateTimeField(
_('Processed'),
auto_now_add=True
)
processed = models.DateTimeField(_("Processed"), auto_now_add=True)
read = models.DateTimeField(
_('Read'),
_("Read"),
default=None,
blank=True,
null=True,
)
eml = models.FileField(
_('Raw message contents'),
_("Raw message contents"),
null=True,
upload_to="messages",
help_text=_('Original full content of message')
help_text=_("Original full content of message"),
)
objects = models.Manager()
unread_messages = UnreadMessageManager()
@ -570,13 +559,9 @@ class Message(models.Model):
def to_addresses(self):
"""Returns a list of addresses to which this message was sent."""
addresses = []
for address in self.to_header.split(','):
for address in self.to_header.split(","):
if address:
addresses.append(
parseaddr(
address
)[1].lower()
)
addresses.append(parseaddr(address)[1].lower())
return addresses
def reply(self, message):
@ -593,14 +578,12 @@ class Message(models.Model):
message.from_email = self.mailbox.from_email
else:
message.from_email = django_settings.DEFAULT_FROM_EMAIL
message.extra_headers['Message-ID'] = make_msgid()
message.extra_headers['Date'] = formatdate()
message.extra_headers['In-Reply-To'] = self.message_id.strip()
message.extra_headers["Message-ID"] = make_msgid()
message.extra_headers["Date"] = formatdate()
message.extra_headers["In-Reply-To"] = self.message_id.strip()
message.send()
return self.mailbox.record_outgoing_message(
email.message_from_string(
message.message().as_string()
)
email.message_from_string(message.message().as_string())
)
@property
@ -608,18 +591,22 @@ class Message(models.Model):
"""
Returns the message body matching content type 'text/plain'.
"""
return utils.get_body_from_message(
self.get_email_object(), 'text', 'plain'
).replace('=\n', '').strip()
return (
utils.get_body_from_message(self.get_email_object(), "text", "plain")
.replace("=\n", "")
.strip()
)
@property
def html(self):
"""
Returns the message body matching content type 'text/html'.
"""
return utils.get_body_from_message(
self.get_email_object(), 'text', 'html'
).replace('\n', '').strip()
return (
utils.get_body_from_message(self.get_email_object(), "text", "html")
.replace("\n", "")
.strip()
)
def _rehydrate(self, msg):
new = EmailMessage()
@ -629,53 +616,43 @@ class Message(models.Model):
for header, value in msg.items():
new[header] = value
for part in msg.get_payload():
new.attach(
self._rehydrate(part)
)
elif settings['attachment_interpolation_header'] in msg.keys():
new.attach(self._rehydrate(part))
elif settings["attachment_interpolation_header"] in msg.keys():
try:
attachment = MessageAttachment.objects.get(
pk=msg[settings['attachment_interpolation_header']]
pk=msg[settings["attachment_interpolation_header"]]
)
for header, value in attachment.items():
new[header] = value
encoding = new['Content-Transfer-Encoding']
if encoding and encoding.lower() == 'quoted-printable':
encoding = new["Content-Transfer-Encoding"]
if encoding and encoding.lower() == "quoted-printable":
# Cannot use `email.encoders.encode_quopri due to
# bug 14360: http://bugs.python.org/issue14360
output = BytesIO()
encode_quopri(
BytesIO(
attachment.document.read()
),
BytesIO(attachment.document.read()),
output,
quotetabs=True,
header=False,
)
new.set_payload(
output.getvalue().decode().replace(' ', '=20')
)
del new['Content-Transfer-Encoding']
new['Content-Transfer-Encoding'] = 'quoted-printable'
new.set_payload(output.getvalue().decode().replace(" ", "=20"))
del new["Content-Transfer-Encoding"]
new["Content-Transfer-Encoding"] = "quoted-printable"
else:
new.set_payload(
attachment.document.read()
)
del new['Content-Transfer-Encoding']
new.set_payload(attachment.document.read())
del new["Content-Transfer-Encoding"]
encode_base64(new)
except MessageAttachment.DoesNotExist:
new[settings['altered_message_header']] = (
'Missing; Attachment %s not found' % (
msg[settings['attachment_interpolation_header']]
new[
settings["altered_message_header"]
] = "Missing; Attachment %s not found" % (
msg[settings["attachment_interpolation_header"]]
)
)
new.set_payload('')
new.set_payload("")
else:
for header, value in msg.items():
new[header] = value
new.set_payload(
msg.get_payload()
)
new.set_payload(msg.get_payload())
return new
def get_body(self):
@ -686,8 +663,8 @@ class Message(models.Model):
"""
if self.encoded:
return base64.b64decode(self.body.encode('ascii'))
return self.body.encode('utf-8')
return base64.b64decode(self.body.encode("ascii"))
return self.body.encode("utf-8")
def set_body(self, body):
"""Set the `body` field of this record.
@ -698,7 +675,7 @@ class Message(models.Model):
"""
self.encoded = True
self.body = base64.b64encode(body.encode('utf-8')).decode('ascii')
self.body = base64.b64encode(body.encode("utf-8")).decode("ascii")
def get_email_object(self):
"""Returns an `email.message.EmailMessage` instance representing the
@ -719,9 +696,9 @@ class Message(models.Model):
(https://docs.python.org/3/library/email.message.html)
"""
if not hasattr(self, '_email_object'): # Cache fill
if not hasattr(self, "_email_object"): # Cache fill
if self.eml:
if self.eml.name.endswith('.gz'):
if self.eml.name.endswith(".gz"):
body = gzip.GzipFile(fileobj=self.eml).read()
else:
self.eml.open()
@ -744,28 +721,28 @@ class Message(models.Model):
return self.subject
class Meta:
verbose_name = _('E-mail message')
verbose_name_plural = _('E-mail messages')
verbose_name = _("E-mail message")
verbose_name_plural = _("E-mail messages")
class MessageAttachment(models.Model):
message = models.ForeignKey(
Message,
related_name='attachments',
related_name="attachments",
null=True,
blank=True,
verbose_name=_('Message'),
on_delete=models.CASCADE
verbose_name=_("Message"),
on_delete=models.CASCADE,
)
headers = models.TextField(
_('Headers'),
_("Headers"),
null=True,
blank=True,
)
document = models.FileField(
_('Document'),
_("Document"),
upload_to=utils.get_attachment_save_path,
)
@ -810,12 +787,12 @@ class MessageAttachment(models.Model):
def __getitem__(self, name):
value = self._get_rehydrated_headers()[name]
if value is None:
raise KeyError('Header %s does not exist' % name)
raise KeyError("Header %s does not exist" % name)
return value
def __str__(self):
return self.document.url
class Meta:
verbose_name = _('Message attachment')
verbose_name_plural = _('Message attachments')
verbose_name = _("Message attachment")
verbose_name_plural = _("Message attachments")

View file

@ -1,3 +1,3 @@
from django.dispatch.dispatcher import Signal
message_received = Signal(providing_args=['message'])
message_received = Signal(providing_args=["message"])

View file

@ -5,54 +5,92 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Mailbox'
db.create_table('django_mailbox_mailbox', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
('uri', self.gf('django.db.models.fields.CharField')(max_length=255)),
))
db.send_create_signal('django_mailbox', ['Mailbox'])
db.create_table(
"django_mailbox_mailbox",
(
("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)),
("name", self.gf("django.db.models.fields.CharField")(max_length=255)),
("uri", self.gf("django.db.models.fields.CharField")(max_length=255)),
),
)
db.send_create_signal("django_mailbox", ["Mailbox"])
# Adding model 'Message'
db.create_table('django_mailbox_message', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('mailbox', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['django_mailbox.Mailbox'])),
('subject', self.gf('django.db.models.fields.CharField')(max_length=255)),
('message_id', self.gf('django.db.models.fields.CharField')(max_length=255)),
('from_address', self.gf('django.db.models.fields.CharField')(max_length=255)),
('body', self.gf('django.db.models.fields.TextField')()),
('received', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
))
db.send_create_signal('django_mailbox', ['Message'])
db.create_table(
"django_mailbox_message",
(
("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)),
(
"mailbox",
self.gf("django.db.models.fields.related.ForeignKey")(
to=orm["django_mailbox.Mailbox"]
),
),
(
"subject",
self.gf("django.db.models.fields.CharField")(max_length=255),
),
(
"message_id",
self.gf("django.db.models.fields.CharField")(max_length=255),
),
(
"from_address",
self.gf("django.db.models.fields.CharField")(max_length=255),
),
("body", self.gf("django.db.models.fields.TextField")()),
(
"received",
self.gf("django.db.models.fields.DateTimeField")(
auto_now_add=True, blank=True
),
),
),
)
db.send_create_signal("django_mailbox", ["Message"])
def backwards(self, orm):
# Deleting model 'Mailbox'
db.delete_table('django_mailbox_mailbox')
db.delete_table("django_mailbox_mailbox")
# Deleting model 'Message'
db.delete_table('django_mailbox_message')
db.delete_table("django_mailbox_message")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'max_length': '255'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_address": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"received": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,34 +5,64 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Mailbox.uri'
db.alter_column('django_mailbox_mailbox', 'uri', self.gf('django.db.models.fields.CharField')(max_length=255, null=True))
db.alter_column(
"django_mailbox_mailbox",
"uri",
self.gf("django.db.models.fields.CharField")(max_length=255, null=True),
)
def backwards(self, orm):
# User chose to not deal with backwards NULL issues for 'Mailbox.uri'
raise RuntimeError("Cannot reverse this migration. 'Mailbox.uri' and its values cannot be restored.")
raise RuntimeError(
"Cannot reverse this migration. 'Mailbox.uri' and its values cannot be restored."
)
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_address": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"received": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,37 +5,62 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Mailbox.active'
db.add_column('django_mailbox_mailbox', 'active',
self.gf('django.db.models.fields.BooleanField')(default=True),
keep_default=False)
db.add_column(
"django_mailbox_mailbox",
"active",
self.gf("django.db.models.fields.BooleanField")(default=True),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'Mailbox.active'
db.delete_column('django_mailbox_mailbox', 'active')
db.delete_column("django_mailbox_mailbox", "active")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_address": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"received": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,38 +5,67 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Message.outgoing'
db.add_column('django_mailbox_message', 'outgoing',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
db.add_column(
"django_mailbox_message",
"outgoing",
self.gf("django.db.models.fields.BooleanField")(default=False),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'Message.outgoing'
db.delete_column('django_mailbox_message', 'outgoing')
db.delete_column("django_mailbox_message", "outgoing")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_address": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"received": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,34 +5,58 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
db.rename_column('django_mailbox_message', 'from_address', 'address')
db.rename_column('django_mailbox_message', 'received', 'processed')
db.rename_column("django_mailbox_message", "from_address", "address")
db.rename_column("django_mailbox_message", "received", "processed")
def backwards(self, orm):
db.rename_column('django_mailbox_message', 'address', 'from_address')
db.rename_column('django_mailbox_message', 'processed', 'received')
db.rename_column("django_mailbox_message", "address", "from_address")
db.rename_column("django_mailbox_message", "processed", "received")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"address": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"body": ("django.db.models.fields.TextField", [], {}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'body': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,51 +5,116 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Message.in_reply_to'
db.add_column('django_mailbox_message', 'in_reply_to',
self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='replies', null=True, to=orm['django_mailbox.Message']),
keep_default=False)
db.add_column(
"django_mailbox_message",
"in_reply_to",
self.gf("django.db.models.fields.related.ForeignKey")(
blank=True,
related_name="replies",
null=True,
to=orm["django_mailbox.Message"],
),
keep_default=False,
)
# Adding M2M table for field references on 'Message'
db.create_table('django_mailbox_message_references', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('from_message', models.ForeignKey(orm['django_mailbox.message'], null=False)),
('to_message', models.ForeignKey(orm['django_mailbox.message'], null=False))
))
db.create_unique('django_mailbox_message_references', ['from_message_id', 'to_message_id'])
db.create_table(
"django_mailbox_message_references",
(
(
"id",
models.AutoField(
verbose_name="ID", primary_key=True, auto_created=True
),
),
(
"from_message",
models.ForeignKey(orm["django_mailbox.message"], null=False),
),
(
"to_message",
models.ForeignKey(orm["django_mailbox.message"], null=False),
),
),
)
db.create_unique(
"django_mailbox_message_references", ["from_message_id", "to_message_id"]
)
def backwards(self, orm):
# Deleting field 'Message.in_reply_to'
db.delete_column('django_mailbox_message', 'in_reply_to_id')
db.delete_column("django_mailbox_message", "in_reply_to_id")
# Removing M2M table for field references on 'Message'
db.delete_table('django_mailbox_message_references')
db.delete_table("django_mailbox_message_references")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"address": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"body": ("django.db.models.fields.TextField", [], {}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"references": (
"django.db.models.fields.related.ManyToManyField",
[],
{
"blank": "True",
"related_name": "'referenced_by'",
"null": "True",
"symmetrical": "False",
"to": "orm['django_mailbox.Message']",
},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'body': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'references': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'referenced_by'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['django_mailbox.Message']"}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,55 +5,108 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting field 'Message.address'
db.delete_column('django_mailbox_message', 'address')
db.delete_column("django_mailbox_message", "address")
# Adding field 'Message.from_header'
db.add_column('django_mailbox_message', 'from_header',
self.gf('django.db.models.fields.CharField')(default='', max_length=255),
keep_default=False)
db.add_column(
"django_mailbox_message",
"from_header",
self.gf("django.db.models.fields.CharField")(default="", max_length=255),
keep_default=False,
)
# Adding field 'Message.to_header'
db.add_column('django_mailbox_message', 'to_header',
self.gf('django.db.models.fields.TextField')(default=''),
keep_default=False)
db.add_column(
"django_mailbox_message",
"to_header",
self.gf("django.db.models.fields.TextField")(default=""),
keep_default=False,
)
def backwards(self, orm):
# User chose to not deal with backwards NULL issues for 'Message.address'
raise RuntimeError("Cannot reverse this migration. 'Message.address' and its values cannot be restored.")
raise RuntimeError(
"Cannot reverse this migration. 'Message.address' and its values cannot be restored."
)
# Deleting field 'Message.from_header'
db.delete_column('django_mailbox_message', 'from_header')
db.delete_column("django_mailbox_message", "from_header")
# Deleting field 'Message.to_header'
db.delete_column('django_mailbox_message', 'to_header')
db.delete_column("django_mailbox_message", "to_header")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"references": (
"django.db.models.fields.related.ManyToManyField",
[],
{
"blank": "True",
"related_name": "'referenced_by'",
"null": "True",
"symmetrical": "False",
"to": "orm['django_mailbox.Message']",
},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'references': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'referenced_by'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['django_mailbox.Message']"}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -4,43 +4,89 @@ from south.db import db
from south.v2 import DataMigration
from django.db import models
class Migration(DataMigration):
class Migration(DataMigration):
def forwards(self, orm):
for message in orm['django_mailbox.message'].objects.all():
msg_object = email.message_from_string(
message.body
)
message.from_header = msg_object['from']
message.to_header = msg_object['to']
for message in orm["django_mailbox.message"].objects.all():
msg_object = email.message_from_string(message.body)
message.from_header = msg_object["from"]
message.to_header = msg_object["to"]
message.save()
def backwards(self, orm):
raise RuntimeError('Cannot reverse this migration.')
raise RuntimeError("Cannot reverse this migration.")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"references": (
"django.db.models.fields.related.ManyToManyField",
[],
{
"blank": "True",
"related_name": "'referenced_by'",
"null": "True",
"symmetrical": "False",
"to": "orm['django_mailbox.Message']",
},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'references': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'referenced_by'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['django_mailbox.Message']"}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]
symmetrical = True

View file

@ -5,43 +5,94 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing M2M table for field references on 'Message'
db.delete_table('django_mailbox_message_references')
db.delete_table("django_mailbox_message_references")
def backwards(self, orm):
# Adding M2M table for field references on 'Message'
db.create_table('django_mailbox_message_references', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('from_message', models.ForeignKey(orm['django_mailbox.message'], null=False)),
('to_message', models.ForeignKey(orm['django_mailbox.message'], null=False))
))
db.create_unique('django_mailbox_message_references', ['from_message_id', 'to_message_id'])
db.create_table(
"django_mailbox_message_references",
(
(
"id",
models.AutoField(
verbose_name="ID", primary_key=True, auto_created=True
),
),
(
"from_message",
models.ForeignKey(orm["django_mailbox.message"], null=False),
),
(
"to_message",
models.ForeignKey(orm["django_mailbox.message"], null=False),
),
),
)
db.create_unique(
"django_mailbox_message_references", ["from_message_id", "to_message_id"]
)
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,41 +5,90 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Mailbox.from_email'
db.add_column('django_mailbox_mailbox', 'from_email',
self.gf('django.db.models.fields.CharField')(default=None, max_length=255, null=True, blank=True),
keep_default=False)
db.add_column(
"django_mailbox_mailbox",
"from_email",
self.gf("django.db.models.fields.CharField")(
default=None, max_length=255, null=True, blank=True
),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'Mailbox.from_email'
db.delete_column('django_mailbox_mailbox', 'from_email')
db.delete_column("django_mailbox_mailbox", "from_email")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,42 +5,95 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Message.read'
db.add_column('django_mailbox_message', 'read',
self.gf('django.db.models.fields.DateTimeField')(default=None, null=True, blank=True),
keep_default=False)
db.add_column(
"django_mailbox_message",
"read",
self.gf("django.db.models.fields.DateTimeField")(
default=None, null=True, blank=True
),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'Message.read'
db.delete_column('django_mailbox_message', 'read')
db.delete_column("django_mailbox_message", "read")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -3,64 +3,148 @@ from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'MessageAttachment'
db.create_table('django_mailbox_messageattachment', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('document', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
))
db.send_create_signal('django_mailbox', ['MessageAttachment'])
db.create_table(
"django_mailbox_messageattachment",
(
("id", self.gf("django.db.models.fields.AutoField")(primary_key=True)),
(
"document",
self.gf("django.db.models.fields.files.FileField")(max_length=100),
),
),
)
db.send_create_signal("django_mailbox", ["MessageAttachment"])
# Adding M2M table for field attachments on 'Message'
db.create_table('django_mailbox_message_attachments', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('message', models.ForeignKey(orm['django_mailbox.message'], null=False)),
('messageattachment', models.ForeignKey(orm['django_mailbox.messageattachment'], null=False))
))
db.create_unique('django_mailbox_message_attachments', ['message_id', 'messageattachment_id'])
db.create_table(
"django_mailbox_message_attachments",
(
(
"id",
models.AutoField(
verbose_name="ID", primary_key=True, auto_created=True
),
),
(
"message",
models.ForeignKey(orm["django_mailbox.message"], null=False),
),
(
"messageattachment",
models.ForeignKey(
orm["django_mailbox.messageattachment"], null=False
),
),
),
)
db.create_unique(
"django_mailbox_message_attachments", ["message_id", "messageattachment_id"]
)
def backwards(self, orm):
# Deleting model 'MessageAttachment'
db.delete_table('django_mailbox_messageattachment')
db.delete_table("django_mailbox_messageattachment")
# Removing M2M table for field attachments on 'Message'
db.delete_table('django_mailbox_message_attachments')
db.delete_table("django_mailbox_message_attachments")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'attachments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['django_mailbox.MessageAttachment']", 'symmetrical': 'False'}),
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"attachments": (
"django.db.models.fields.related.ManyToManyField",
[],
{
"to": "orm['django_mailbox.MessageAttachment']",
"symmetrical": "False",
},
),
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
"django_mailbox.messageattachment": {
"Meta": {"object_name": "MessageAttachment"},
"document": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
},
'django_mailbox.messageattachment': {
'Meta': {'object_name': 'MessageAttachment'},
'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,49 +5,127 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'MessageAttachment.message'
db.add_column('django_mailbox_messageattachment', 'message',
self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='attachments', null=True, to=orm['django_mailbox.Message']),
keep_default=False)
db.add_column(
"django_mailbox_messageattachment",
"message",
self.gf("django.db.models.fields.related.ForeignKey")(
blank=True,
related_name="attachments",
null=True,
to=orm["django_mailbox.Message"],
),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'MessageAttachment.message'
db.delete_column('django_mailbox_messageattachment', 'message_id')
db.delete_column("django_mailbox_messageattachment", "message_id")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'attachments': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'messages_old'", 'blank': 'True', 'to': "orm['django_mailbox.MessageAttachment']"}),
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"attachments": (
"django.db.models.fields.related.ManyToManyField",
[],
{
"symmetrical": "False",
"related_name": "'messages_old'",
"blank": "True",
"to": "orm['django_mailbox.MessageAttachment']",
},
),
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
"django_mailbox.messageattachment": {
"Meta": {"object_name": "MessageAttachment"},
"document": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"message": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'attachments_new'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
},
'django_mailbox.messageattachment': {
'Meta': {'object_name': 'MessageAttachment'},
'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments_new'", 'null': 'True', 'to': "orm['django_mailbox.Message']"})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -6,49 +6,121 @@ from django.db import models
class Migration(SchemaMigration):
no_dry_run = True
def forwards(self, orm):
for message in orm['django_mailbox.Message'].objects.all():
for message in orm["django_mailbox.Message"].objects.all():
for attachment in message.attachments.all():
attachment.message = message
attachment.save()
def backwards(self, orm):
for attachment in orm['django_mailbox.MessageAttachment'].objects.all():
for attachment in orm["django_mailbox.MessageAttachment"].objects.all():
if attachment.message:
attachment.message.attachments.add(
attachment
)
attachment.message.attachments.add(attachment)
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'attachments': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'messages_old'", 'blank': 'True', 'to': "orm['django_mailbox.MessageAttachment']"}),
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"attachments": (
"django.db.models.fields.related.ManyToManyField",
[],
{
"symmetrical": "False",
"related_name": "'messages_old'",
"blank": "True",
"to": "orm['django_mailbox.MessageAttachment']",
},
),
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
"django_mailbox.messageattachment": {
"Meta": {"object_name": "MessageAttachment"},
"document": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"message": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'attachments_new'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
},
'django_mailbox.messageattachment': {
'Meta': {'object_name': 'MessageAttachment'},
'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments_new'", 'null': 'True', 'to': "orm['django_mailbox.Message']"})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,60 +5,146 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing M2M table for field attachments on 'Message'
db.delete_table('django_mailbox_message_attachments')
db.delete_table("django_mailbox_message_attachments")
# Adding field 'MessageAttachment.headers'
db.add_column('django_mailbox_messageattachment', 'headers',
self.gf('django.db.models.fields.TextField')(null=True, blank=True),
keep_default=False)
db.add_column(
"django_mailbox_messageattachment",
"headers",
self.gf("django.db.models.fields.TextField")(null=True, blank=True),
keep_default=False,
)
def backwards(self, orm):
# Adding M2M table for field attachments on 'Message'
db.create_table('django_mailbox_message_attachments', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('message', models.ForeignKey(orm['django_mailbox.message'], null=False)),
('messageattachment', models.ForeignKey(orm['django_mailbox.messageattachment'], null=False))
))
db.create_unique('django_mailbox_message_attachments', ['message_id', 'messageattachment_id'])
db.create_table(
"django_mailbox_message_attachments",
(
(
"id",
models.AutoField(
verbose_name="ID", primary_key=True, auto_created=True
),
),
(
"message",
models.ForeignKey(orm["django_mailbox.message"], null=False),
),
(
"messageattachment",
models.ForeignKey(
orm["django_mailbox.messageattachment"], null=False
),
),
),
)
db.create_unique(
"django_mailbox_message_attachments", ["message_id", "messageattachment_id"]
)
# Deleting field 'MessageAttachment.headers'
db.delete_column('django_mailbox_messageattachment', 'headers')
db.delete_column("django_mailbox_messageattachment", "headers")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
"django_mailbox.messageattachment": {
"Meta": {"object_name": "MessageAttachment"},
"document": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100"},
),
"headers": (
"django.db.models.fields.TextField",
[],
{"null": "True", "blank": "True"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"message": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'attachments'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
},
'django_mailbox.messageattachment': {
'Meta': {'object_name': 'MessageAttachment'},
'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments'", 'null': 'True', 'to': "orm['django_mailbox.Message']"})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,50 +5,122 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Message.encoded'
db.add_column('django_mailbox_message', 'encoded',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
db.add_column(
"django_mailbox_message",
"encoded",
self.gf("django.db.models.fields.BooleanField")(default=False),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'Message.encoded'
db.delete_column('django_mailbox_message', 'encoded')
db.delete_column("django_mailbox_message", "encoded")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'encoded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"encoded": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
"django_mailbox.messageattachment": {
"Meta": {"object_name": "MessageAttachment"},
"document": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100"},
),
"headers": (
"django.db.models.fields.TextField",
[],
{"null": "True", "blank": "True"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"message": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'attachments'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
},
'django_mailbox.messageattachment': {
'Meta': {'object_name': 'MessageAttachment'},
'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments'", 'null': 'True', 'to': "orm['django_mailbox.Message']"})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -5,51 +5,129 @@ from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Message.eml'
db.add_column('django_mailbox_message', 'eml',
self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True),
keep_default=False)
db.add_column(
"django_mailbox_message",
"eml",
self.gf("django.db.models.fields.files.FileField")(
max_length=100, null=True
),
keep_default=False,
)
def backwards(self, orm):
# Deleting field 'Message.eml'
db.delete_column('django_mailbox_message', 'eml')
db.delete_column("django_mailbox_message", "eml")
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'from_email': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'})
"django_mailbox.mailbox": {
"Meta": {"object_name": "Mailbox"},
"active": ("django.db.models.fields.BooleanField", [], {"default": "True"}),
"from_email": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'eml': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True'}),
'encoded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'from_header': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'in_reply_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'replies'", 'null': 'True', 'to': "orm['django_mailbox.Message']"}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'outgoing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'processed': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'read': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'to_header': ('django.db.models.fields.TextField', [], {})
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"name": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"uri": (
"django.db.models.fields.CharField",
[],
{
"default": "None",
"max_length": "255",
"null": "True",
"blank": "True",
},
),
},
"django_mailbox.message": {
"Meta": {"object_name": "Message"},
"body": ("django.db.models.fields.TextField", [], {}),
"eml": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100", "null": "True"},
),
"encoded": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"from_header": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"in_reply_to": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'replies'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
"mailbox": (
"django.db.models.fields.related.ForeignKey",
[],
{"related_name": "'messages'", "to": "orm['django_mailbox.Mailbox']"},
),
"message_id": (
"django.db.models.fields.CharField",
[],
{"max_length": "255"},
),
"outgoing": (
"django.db.models.fields.BooleanField",
[],
{"default": "False"},
),
"processed": (
"django.db.models.fields.DateTimeField",
[],
{"auto_now_add": "True", "blank": "True"},
),
"read": (
"django.db.models.fields.DateTimeField",
[],
{"default": "None", "null": "True", "blank": "True"},
),
"subject": ("django.db.models.fields.CharField", [], {"max_length": "255"}),
"to_header": ("django.db.models.fields.TextField", [], {}),
},
"django_mailbox.messageattachment": {
"Meta": {"object_name": "MessageAttachment"},
"document": (
"django.db.models.fields.files.FileField",
[],
{"max_length": "100"},
),
"headers": (
"django.db.models.fields.TextField",
[],
{"null": "True", "blank": "True"},
),
"id": ("django.db.models.fields.AutoField", [], {"primary_key": "True"}),
"message": (
"django.db.models.fields.related.ForeignKey",
[],
{
"blank": "True",
"related_name": "'attachments'",
"null": "True",
"to": "orm['django_mailbox.Message']",
},
),
},
'django_mailbox.messageattachment': {
'Meta': {'object_name': 'MessageAttachment'},
'document': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'headers': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'attachments'", 'null': 'True', 'to': "orm['django_mailbox.Message']"})
}
}
complete_apps = ['django_mailbox']
complete_apps = ["django_mailbox"]

View file

@ -17,39 +17,37 @@ def get_email_as_text(name):
with open(
os.path.join(
os.path.dirname(__file__),
'messages',
"messages",
name,
),
'rb'
"rb",
) as f:
return f.read()
class EmailMessageTestCase(TestCase):
ALLOWED_EXTRA_HEADERS = [
'MIME-Version',
'Content-Transfer-Encoding',
"MIME-Version",
"Content-Transfer-Encoding",
]
def setUp(self):
dm_settings = utils.get_settings()
self._ALLOWED_MIMETYPES = dm_settings['allowed_mimetypes']
self._STRIP_UNALLOWED_MIMETYPES = (
dm_settings['strip_unallowed_mimetypes']
)
self._TEXT_STORED_MIMETYPES = dm_settings['text_stored_mimetypes']
self._ALLOWED_MIMETYPES = dm_settings["allowed_mimetypes"]
self._STRIP_UNALLOWED_MIMETYPES = dm_settings["strip_unallowed_mimetypes"]
self._TEXT_STORED_MIMETYPES = dm_settings["text_stored_mimetypes"]
self.mailbox = Mailbox.objects.create(from_email='from@example.com')
self.mailbox = Mailbox.objects.create(from_email="from@example.com")
self.test_account = os.environ.get('EMAIL_ACCOUNT')
self.test_password = os.environ.get('EMAIL_PASSWORD')
self.test_smtp_server = os.environ.get('EMAIL_SMTP_SERVER')
self.test_from_email = 'nobody@nowhere.com'
self.test_account = os.environ.get("EMAIL_ACCOUNT")
self.test_password = os.environ.get("EMAIL_PASSWORD")
self.test_smtp_server = os.environ.get("EMAIL_SMTP_SERVER")
self.test_from_email = "nobody@nowhere.com"
self.maximum_wait_seconds = 60 * 5
settings.EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
settings.EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
settings.EMAIL_HOST = self.test_smtp_server
settings.EMAIL_PORT = 587
settings.EMAIL_HOST_USER = self.test_account
@ -80,10 +78,10 @@ class EmailMessageTestCase(TestCase):
with open(
os.path.join(
os.path.dirname(__file__),
'messages',
"messages",
name,
),
'rb'
"rb",
) as f:
return f.read()
@ -103,15 +101,15 @@ class EmailMessageTestCase(TestCase):
the e-mail message.
"""
if header.lower() == 'content-type':
if header.lower() == "content-type":
# Special case; given that we re-write the header, we'll be quoting
# the new content type; we need to make sure that doesn't cause
# this comparison to fail. Also, the case of the encoding could
# be changed, etc. etc. etc.
left = left.replace('"', '').upper()
right = right.replace('"', '').upper()
left = left.replace('\n\t', ' ').replace('\n ', ' ')
right = right.replace('\n\t', ' ').replace('\n ', ' ')
left = left.replace('"', "").upper()
right = right.replace('"', "").upper()
left = left.replace("\n\t", " ").replace("\n ", " ")
right = right.replace("\n\t", " ").replace("\n ", " ")
if right != left:
return False
return True
@ -152,10 +150,7 @@ class EmailMessageTestCase(TestCase):
if len(left_payloads) != len(right_payloads):
self._raise_mismatched(left, right)
for n in range(len(left_payloads)):
self.compare_email_objects(
left_payloads[n],
right_payloads[n]
)
self.compare_email_objects(left_payloads[n], right_payloads[n])
else:
if left.get_payload() is None or right.get_payload() is None:
if left.get_payload() is None:
@ -170,8 +165,7 @@ class EmailMessageTestCase(TestCase):
def _raise_mismatched(self, left, right):
raise AssertionError(
"Message payloads do not match:\n{}\n{}".format(
left.as_string(),
right.as_string()
left.as_string(), right.as_string()
)
)

View file

@ -1,12 +1,12 @@
DATABASES = {
'default': {
'NAME': 'db.sqlite3',
'ENGINE': 'django.db.backends.sqlite3',
"default": {
"NAME": "db.sqlite3",
"ENGINE": "django.db.backends.sqlite3",
},
}
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django_mailbox',
"django.contrib.auth",
"django.contrib.contenttypes",
"django_mailbox",
]
SECRET_KEY = 'beepboop'
SECRET_KEY = "beepboop"

View file

@ -8,16 +8,14 @@ from django_mailbox.models import Mailbox
from django_mailbox.tests.base import EmailMessageTestCase
__all__ = ['TestImap']
__all__ = ["TestImap"]
class TestImap(EmailMessageTestCase):
def setUp(self):
super().setUp()
self.test_imap_server = (
os.environ.get('EMAIL_IMAP_SERVER')
)
self.test_imap_server = os.environ.get("EMAIL_IMAP_SERVER")
required_settings = [
self.test_imap_server,
@ -35,8 +33,7 @@ class TestImap(EmailMessageTestCase):
)
self.mailbox = Mailbox.objects.create(
name='Integration Test Imap',
uri=self.get_connection_string()
name="Integration Test Imap", uri=self.get_connection_string()
)
self.arbitrary_identifier = str(uuid.uuid4())
@ -48,20 +45,19 @@ class TestImap(EmailMessageTestCase):
)
def test_get_imap_message(self):
text_content = 'This is some content'
text_content = "This is some content"
msg = EmailMultiAlternatives(
self.arbitrary_identifier,
text_content,
self.test_from_email,
[
self.test_account,
]
],
)
msg.send()
messages = self._get_new_messages(
self.mailbox,
condition=lambda m: m['subject'] == self.arbitrary_identifier
self.mailbox, condition=lambda m: m["subject"] == self.arbitrary_identifier
)
message = next(messages)

View file

@ -5,15 +5,15 @@ from django.test import TestCase
from django_mailbox.models import Mailbox
__all__ = ['TestMailbox']
__all__ = ["TestMailbox"]
class TestMailbox(TestCase):
def test_protocol_info(self):
mailbox = Mailbox()
mailbox.uri = 'alpha://test.com'
mailbox.uri = "alpha://test.com"
expected_protocol = 'alpha'
expected_protocol = "alpha"
actual_protocol = mailbox._protocol_info.scheme
self.assertEqual(
@ -23,24 +23,30 @@ class TestMailbox(TestCase):
def test_last_polling_field_exists(self):
mailbox = Mailbox()
self.assertTrue(hasattr(mailbox, 'last_polling'))
self.assertTrue(hasattr(mailbox, "last_polling"))
def test_get_new_mail_update_last_polling(self):
mailbox = Mailbox.objects.create(uri="mbox://" + os.path.join(
mailbox = Mailbox.objects.create(
uri="mbox://"
+ os.path.join(
os.path.dirname(__file__),
'messages',
'generic_message.eml',
))
"messages",
"generic_message.eml",
)
)
self.assertEqual(mailbox.last_polling, None)
list(mailbox.get_new_mail())
self.assertNotEqual(mailbox.last_polling, None)
def test_queryset_get_new_mail(self):
mailbox = Mailbox.objects.create(uri="mbox://" + os.path.join(
mailbox = Mailbox.objects.create(
uri="mbox://"
+ os.path.join(
os.path.dirname(__file__),
'messages',
'generic_message.eml',
))
"messages",
"generic_message.eml",
)
)
Mailbox.objects.filter(pk=mailbox.pk).get_new_mail()
mailbox.refresh_from_db()
self.assertNotEqual(mailbox.last_polling, None)

View file

@ -7,20 +7,20 @@ from django_mailbox.models import Message
from django_mailbox.tests.base import EmailMessageTestCase
__all__ = ['TestMessageFlattening']
__all__ = ["TestMessageFlattening"]
class TestMessageFlattening(EmailMessageTestCase):
def test_quopri_message_is_properly_rehydrated(self):
incoming_email_object = self._get_email_object(
'message_with_many_multiparts.eml',
"message_with_many_multiparts.eml",
)
# Note: this is identical to the above, but it appears that
# while reading-in an e-mail message, we do alter it slightly
expected_email_object = self._get_email_object(
'message_with_many_multiparts.eml',
"message_with_many_multiparts.eml",
)
models.TEXT_STORED_MIMETYPES = ['text/plain']
models.TEXT_STORED_MIMETYPES = ["text/plain"]
msg = self.mailbox.process_incoming_message(incoming_email_object)
@ -33,12 +33,12 @@ class TestMessageFlattening(EmailMessageTestCase):
def test_base64_message_is_properly_rehydrated(self):
incoming_email_object = self._get_email_object(
'message_with_attachment.eml',
"message_with_attachment.eml",
)
# Note: this is identical to the above, but it appears that
# while reading-in an e-mail message, we do alter it slightly
expected_email_object = self._get_email_object(
'message_with_attachment.eml',
"message_with_attachment.eml",
)
msg = self.mailbox.process_incoming_message(incoming_email_object)
@ -52,10 +52,10 @@ class TestMessageFlattening(EmailMessageTestCase):
def test_message_handles_rehydration_problems(self):
incoming_email_object = self._get_email_object(
'message_with_defective_attachment_association.eml',
"message_with_defective_attachment_association.eml",
)
expected_email_object = self._get_email_object(
'message_with_defective_attachment_association_result.eml',
"message_with_defective_attachment_association_result.eml",
)
# Note: this is identical to the above, but it appears that
# while reading-in an e-mail message, we do alter it slightly
@ -74,17 +74,17 @@ class TestMessageFlattening(EmailMessageTestCase):
def test_message_content_type_stripping(self):
incoming_email_object = self._get_email_object(
'message_with_many_multiparts.eml',
"message_with_many_multiparts.eml",
)
expected_email_object = self._get_email_object(
'message_with_many_multiparts_stripped_html.eml',
"message_with_many_multiparts_stripped_html.eml",
)
default_settings = utils.get_settings()
with mock.patch('django_mailbox.utils.get_settings') as get_settings:
with mock.patch("django_mailbox.utils.get_settings") as get_settings:
altered = copy.deepcopy(default_settings)
altered['strip_unallowed_mimetypes'] = True
altered['allowed_mimetypes'] = ['text/plain']
altered["strip_unallowed_mimetypes"] = True
altered["allowed_mimetypes"] = ["text/plain"]
get_settings.return_value = altered
@ -100,7 +100,7 @@ class TestMessageFlattening(EmailMessageTestCase):
def test_message_processing_unknown_encoding(self):
incoming_email_object = self._get_email_object(
'message_with_invalid_encoding.eml',
"message_with_invalid_encoding.eml",
)
msg = self.mailbox.process_incoming_message(incoming_email_object)

View file

@ -1,6 +1,7 @@
import gzip
import os.path
import sys
# import sys
import copy
from unittest import mock
@ -12,64 +13,56 @@ from django_mailbox.tests.base import EmailMessageTestCase
from django.utils.encoding import force_text
from django.core.mail import EmailMessage
__all__ = ['TestProcessEmail']
__all__ = ["TestProcessEmail"]
class TestProcessEmail(EmailMessageTestCase):
def test_message_without_attachments(self):
message = self._get_email_object('generic_message.eml')
message = self._get_email_object("generic_message.eml")
mailbox = Mailbox.objects.create()
msg = mailbox.process_incoming_message(message)
self.assertEqual(
msg.mailbox,
mailbox
)
self.assertEqual(msg.subject, 'Message Without Attachment')
self.assertEqual(msg.mailbox, mailbox)
self.assertEqual(msg.subject, "Message Without Attachment")
self.assertEqual(
msg.message_id,
(
'<CAMdmm+hGH8Dgn-_0xnXJCd=PhyNAiouOYm5zFP0z'
'-foqTO60zA@mail.gmail.com>'
)
("<CAMdmm+hGH8Dgn-_0xnXJCd=PhyNAiouOYm5zFP0z" "-foqTO60zA@mail.gmail.com>"),
)
self.assertEqual(
msg.from_header,
'Adam Coddington <test@adamcoddington.net>',
"Adam Coddington <test@adamcoddington.net>",
)
self.assertEqual(
msg.to_header,
'Adam Coddington <test@adamcoddington.net>',
"Adam Coddington <test@adamcoddington.net>",
)
def test_message_with_encoded_attachment_filenames(self):
message = self._get_email_object(
'message_with_koi8r_filename_attachments.eml'
)
message = self._get_email_object("message_with_koi8r_filename_attachments.eml")
mailbox = Mailbox.objects.create()
msg = mailbox.process_incoming_message(message)
attachments = msg.attachments.order_by('pk').all()
attachments = msg.attachments.order_by("pk").all()
self.assertEqual(
'\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b'
'\u043e\u0436\u0435\u043d\u0438\u0439 HSE Career Fair 8 \u0430'
'\u043f\u0440\u0435\u043b\u044f 2016.pdf',
attachments[0].get_filename()
"\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b"
"\u043e\u0436\u0435\u043d\u0438\u0439 HSE Career Fair 8 \u0430"
"\u043f\u0440\u0435\u043b\u044f 2016.pdf",
attachments[0].get_filename(),
)
self.assertEqual(
'\u0412\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u0438.pdf',
attachments[1].get_filename()
"\u0412\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u0438.pdf",
attachments[1].get_filename(),
)
self.assertEqual(
'\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b'
'\u043e\u0436\u0435\u043d\u0438\u0439 2016.pptx',
attachments[2].get_filename()
"\u041f\u0430\u043a\u0435\u0442 \u043f\u0440\u0435\u0434\u043b"
"\u043e\u0436\u0435\u043d\u0438\u0439 2016.pptx",
attachments[2].get_filename(),
)
def test_message_with_attachments(self):
message = self._get_email_object('message_with_attachment.eml')
message = self._get_email_object("message_with_attachment.eml")
mailbox = Mailbox.objects.create()
msg = mailbox.process_incoming_message(message)
@ -85,7 +78,7 @@ class TestProcessEmail(EmailMessageTestCase):
attachment = msg.attachments.all()[0]
self.assertEqual(
attachment.get_filename(),
'heart.png',
"heart.png",
)
def test_message_with_utf8_attachment_header(self):
@ -94,7 +87,7 @@ class TestProcessEmail(EmailMessageTestCase):
Safe for regress of #104 too
"""
email_object = self._get_email_object(
'message_with_utf8_attachment.eml',
"message_with_utf8_attachment.eml",
)
mailbox = Mailbox.objects.create()
msg = mailbox.process_incoming_message(email_object)
@ -108,24 +101,18 @@ class TestProcessEmail(EmailMessageTestCase):
)
attachment = msg.attachments.all()[0]
self.assertEqual(
attachment.get_filename(),
'pi\u0142kochwyty.jpg'
)
self.assertEqual(attachment.get_filename(), "pi\u0142kochwyty.jpg")
attachment = msg.attachments.all()[1]
self.assertEqual(
attachment.get_filename(),
'odpowied\u017a Burmistrza.jpg'
)
self.assertEqual(attachment.get_filename(), "odpowied\u017a Burmistrza.jpg")
def test_message_get_text_body(self):
message = self._get_email_object('multipart_text.eml')
message = self._get_email_object("multipart_text.eml")
mailbox = Mailbox.objects.create()
msg = mailbox.process_incoming_message(message)
expected_results = 'Hello there!'
expected_results = "Hello there!"
actual_results = msg.text.strip()
self.assertEqual(
@ -135,29 +122,21 @@ class TestProcessEmail(EmailMessageTestCase):
def test_get_text_body_properly_recomposes_line_continuations(self):
message = Message()
email_object = self._get_email_object(
'message_with_long_text_lines.eml'
)
email_object = self._get_email_object("message_with_long_text_lines.eml")
message.get_email_object = lambda: email_object
actual_text = message.text
expected_text = (
'The one of us with a bike pump is far ahead, '
'but a man stopped to help us and gave us his pump.'
"The one of us with a bike pump is far ahead, "
"but a man stopped to help us and gave us his pump."
)
self.assertEqual(
actual_text,
expected_text
)
self.assertEqual(actual_text, expected_text)
def test_get_body_properly_handles_unicode_body(self):
with open(
os.path.join(
os.path.dirname(__file__),
'messages/generic_message.eml'
)
os.path.join(os.path.dirname(__file__), "messages/generic_message.eml")
) as f:
unicode_body = f.read()
@ -167,23 +146,18 @@ class TestProcessEmail(EmailMessageTestCase):
expected_body = unicode_body
actual_body = message.get_email_object().as_string()
self.assertEqual(
expected_body,
actual_body
)
self.assertEqual(expected_body, actual_body)
def test_message_issue_82(self):
""" Ensure that we properly handle incorrectly encoded messages
"""
email_object = self._get_email_object('email_issue_82.eml')
it = 'works'
"""Ensure that we properly handle incorrectly encoded messages"""
email_object = self._get_email_object("email_issue_82.eml")
it = "works"
try:
# it's ok to call as_string() before passing email_object
# to _get_dehydrated_message()
email_object.as_string()
except:
it = 'do not works'
except Exception:
it = "do not works"
success = True
try:
@ -191,7 +165,7 @@ class TestProcessEmail(EmailMessageTestCase):
except ValueError:
success = False
self.assertEqual(it, 'works')
self.assertEqual(it, "works")
self.assertEqual(True, success)
def test_message_issue_82_bis(self):
@ -199,7 +173,7 @@ class TestProcessEmail(EmailMessageTestCase):
calling _get_dehydrated_message()
"""
message = self._get_email_object('email_issue_82.eml')
message = self._get_email_object("email_issue_82.eml")
success = True
@ -209,16 +183,16 @@ class TestProcessEmail(EmailMessageTestCase):
# msg.eml.save('%s.eml' % uuid.uuid4(), ContentFile(message),
# save=False)
msg.mailbox = self.mailbox
if 'subject' in message:
msg.subject = convert_header_to_unicode(message['subject'])[0:255]
if 'message-id' in message:
msg.message_id = message['message-id'][0:255]
if 'from' in message:
msg.from_header = convert_header_to_unicode(message['from'])
if 'to' in message:
msg.to_header = convert_header_to_unicode(message['to'])
elif 'Delivered-To' in message:
msg.to_header = convert_header_to_unicode(message['Delivered-To'])
if "subject" in message:
msg.subject = convert_header_to_unicode(message["subject"])[0:255]
if "message-id" in message:
msg.message_id = message["message-id"][0:255]
if "from" in message:
msg.from_header = convert_header_to_unicode(message["from"])
if "to" in message:
msg.to_header = convert_header_to_unicode(message["to"])
elif "Delivered-To" in message:
msg.to_header = convert_header_to_unicode(message["Delivered-To"])
msg.save()
# here the message is ok
@ -227,14 +201,14 @@ class TestProcessEmail(EmailMessageTestCase):
try:
# here as_string raises UnicodeEncodeError
str_msg = message.as_string()
except:
except Exception:
success = False
msg.set_body(str_msg)
if message['in-reply-to']:
if message["in-reply-to"]:
try:
msg.in_reply_to = Message.objects.filter(
message_id=message['in-reply-to']
message_id=message["in-reply-to"]
)[0]
except IndexError:
pass
@ -249,12 +223,14 @@ class TestProcessEmail(EmailMessageTestCase):
as being iso-8859-1 data, but actually contains UTF-8 bytes.
"""
email_object = self._get_email_object('message_with_utf8_char.eml')
email_object = self._get_email_object("message_with_utf8_char.eml")
msg = self.mailbox.process_incoming_message(email_object)
expected_text = 'This message contains funny UTF16 characters ' + \
'like this one: "\xc2\xa0" and this one "\xe2\x9c\xbf".'
expected_text = (
"This message contains funny UTF16 characters "
+ 'like this one: "\xc2\xa0" and this one "\xe2\x9c\xbf".'
)
actual_text = msg.text
self.assertEqual(
@ -275,7 +251,7 @@ class TestProcessEmail(EmailMessageTestCase):
"""
email_object = self._get_email_object(
'message_with_invalid_content_for_declared_encoding.eml',
"message_with_invalid_content_for_declared_encoding.eml",
)
msg = self.mailbox.process_incoming_message(email_object)
@ -284,18 +260,20 @@ class TestProcessEmail(EmailMessageTestCase):
def test_message_with_valid_content_in_single_byte_encoding(self):
email_object = self._get_email_object(
'message_with_single_byte_encoding.eml',
"message_with_single_byte_encoding.eml",
)
msg = self.mailbox.process_incoming_message(email_object)
actual_text = msg.text
expected_body = '\u042d\u0442\u043e ' + \
'\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 ' + \
'\u0438\u043c\u0435\u0435\u0442 ' + \
'\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d' + \
'\u0443\u044e ' + \
'\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430.'
expected_body = (
"\u042d\u0442\u043e "
+ "\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 "
+ "\u0438\u043c\u0435\u0435\u0442 "
+ "\u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d"
+ "\u0443\u044e "
+ "\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430."
)
self.assertEqual(
actual_text,
@ -304,42 +282,44 @@ class TestProcessEmail(EmailMessageTestCase):
def test_message_with_single_byte_subject_encoding(self):
email_object = self._get_email_object(
'message_with_single_byte_extended_subject_encoding.eml',
"message_with_single_byte_extended_subject_encoding.eml",
)
msg = self.mailbox.process_incoming_message(email_object)
expected_subject = '\u00D3\u00E7\u00ED\u00E0\u00E9 \u00EA\u00E0\u00EA ' + \
'\u00E7\u00E0\u00F0\u00E0\u00E1\u00E0\u00F2\u00FB\u00E2' + \
'\u00E0\u00F2\u00FC \u00EE\u00F2 1000$ \u00E2 ' + \
'\u00ED\u00E5\u00E4\u00E5\u00EB\u00FE!'
expected_subject = (
"\u00D3\u00E7\u00ED\u00E0\u00E9 \u00EA\u00E0\u00EA "
+ "\u00E7\u00E0\u00F0\u00E0\u00E1\u00E0\u00F2\u00FB\u00E2"
+ "\u00E0\u00F2\u00FC \u00EE\u00F2 1000$ \u00E2 "
+ "\u00ED\u00E5\u00E4\u00E5\u00EB\u00FE!"
)
actual_subject = msg.subject
self.assertEqual(actual_subject, expected_subject)
expected_from = 'test test <mr.test32@mail.ru>'
expected_from = "test test <mr.test32@mail.ru>"
actual_from = msg.from_header
self.assertEqual(expected_from, actual_from)
def test_message_reply(self):
email_object = EmailMessage(
'Test subject', # subject
'Test body', # body
'username@example.com', # from
['mr.test32@mail.ru'], # to
"Test subject", # subject
"Test body", # body
"username@example.com", # from
["mr.test32@mail.ru"], # to
)
msg = self.mailbox.record_outgoing_message(email_object.message())
self.assertTrue(msg.outgoing)
actual_from = 'username@example.com'
actual_from = "username@example.com"
reply_email_object = EmailMessage(
'Test subject', # subject
'Test body', # body
"Test subject", # subject
"Test body", # body
actual_from, # from
['mr.test32@mail.ru'], # to
["mr.test32@mail.ru"], # to
)
with mock.patch.object(reply_email_object, 'send'):
with mock.patch.object(reply_email_object, "send"):
reply_msg = msg.reply(reply_email_object)
self.assertEqual(reply_msg.in_reply_to, msg)
@ -348,62 +328,58 @@ class TestProcessEmail(EmailMessageTestCase):
reply_email_object.from_email = None
with mock.patch.object(reply_email_object, 'send'):
with mock.patch.object(reply_email_object, "send"):
second_reply_msg = msg.reply(reply_email_object)
self.assertEqual(self.mailbox.from_email, second_reply_msg.from_header)
def test_message_with_text_attachment(self):
email_object = self._get_email_object(
'message_with_text_attachment.eml',
"message_with_text_attachment.eml",
)
msg = self.mailbox.process_incoming_message(email_object)
self.assertEqual(msg.attachments.all().count(), 1)
self.assertEqual('Has an attached text document, too!', msg.text)
self.assertEqual("Has an attached text document, too!", msg.text)
def test_message_with_long_content(self):
email_object = self._get_email_object(
'message_with_long_content.eml',
"message_with_long_content.eml",
)
size = len(force_text(email_object.as_string()))
msg = self.mailbox.process_incoming_message(email_object)
self.assertEqual(size,
len(force_text(msg.get_email_object().as_string())))
self.assertEqual(size, len(force_text(msg.get_email_object().as_string())))
def test_message_saved(self):
message = self._get_email_object('generic_message.eml')
message = self._get_email_object("generic_message.eml")
default_settings = utils.get_settings()
with mock.patch('django_mailbox.utils.get_settings') as get_settings:
with mock.patch("django_mailbox.utils.get_settings") as get_settings:
altered = copy.deepcopy(default_settings)
altered['store_original_message'] = True
altered["store_original_message"] = True
get_settings.return_value = altered
msg = self.mailbox.process_incoming_message(message)
self.assertNotEquals(msg.eml, None)
self.assertTrue(msg.eml.name.endswith('.eml'))
self.assertTrue(msg.eml.name.endswith(".eml"))
with open(msg.eml.name, 'rb') as f:
self.assertEqual(
f.read(),
self._get_email_as_text('generic_message.eml')
)
with open(msg.eml.name, "rb") as f:
self.assertEqual(f.read(), self._get_email_as_text("generic_message.eml"))
def test_message_saving_ignored(self):
message = self._get_email_object('generic_message.eml')
message = self._get_email_object("generic_message.eml")
default_settings = utils.get_settings()
with mock.patch('django_mailbox.utils.get_settings') as get_settings:
with mock.patch("django_mailbox.utils.get_settings") as get_settings:
altered = copy.deepcopy(default_settings)
altered['store_original_message'] = False
altered["store_original_message"] = False
get_settings.return_value = altered
msg = self.mailbox.process_incoming_message(message)
@ -411,22 +387,21 @@ class TestProcessEmail(EmailMessageTestCase):
self.assertEquals(msg.eml, None)
def test_message_compressed(self):
message = self._get_email_object('generic_message.eml')
message = self._get_email_object("generic_message.eml")
default_settings = utils.get_settings()
with mock.patch('django_mailbox.utils.get_settings') as get_settings:
with mock.patch("django_mailbox.utils.get_settings") as get_settings:
altered = copy.deepcopy(default_settings)
altered['compress_original_message'] = True
altered['store_original_message'] = True
altered["compress_original_message"] = True
altered["store_original_message"] = True
get_settings.return_value = altered
msg = self.mailbox.process_incoming_message(message)
actual_email_object = msg.get_email_object()
print(actual_email_object)
self.assertTrue(msg.eml.name.endswith(".eml.gz"))
self.assertTrue(msg.eml.name.endswith('.eml.gz'))
with gzip.open(msg.eml.name, 'rb') as f:
self.assertEqual(f.read(),
self._get_email_as_text('generic_message.eml'))
with gzip.open(msg.eml.name, "rb") as f:
self.assertEqual(f.read(), self._get_email_as_text("generic_message.eml"))

View file

@ -5,6 +5,7 @@ from django.core.management import call_command, CommandError
from django.test import TestCase
import django
class CommandsTestCase(TestCase):
def test_processincomingmessage_no_args(self):
"""Check that processincomingmessage works with no args"""
@ -12,16 +13,18 @@ class CommandsTestCase(TestCase):
mailbox_name = None
# Mock handle so that the test doesn't hang waiting for input. Note that we are only testing
# the argument parsing here -- functionality should be tested elsewhere
with mock.patch('django_mailbox.management.commands.processincomingmessage.Command.handle') as handle:
with mock.patch(
"django_mailbox.management.commands.processincomingmessage.Command.handle"
) as handle:
# Don't care about the return value
handle.return_value = None
call_command('processincomingmessage')
call_command("processincomingmessage")
args, kwargs = handle.call_args
# Make sure that we called with the right arguments
try:
self.assertEqual(kwargs['mailbox_name'], mailbox_name)
self.assertEqual(kwargs["mailbox_name"], mailbox_name)
except KeyError:
# Handle Django 1.7
# It uses optparse instead of argparse, so instead of being
@ -29,19 +32,20 @@ class CommandsTestCase(TestCase):
# Thus we expect an empty tuple here
self.assertEqual(args, tuple())
def test_processincomingmessage_with_arg(self):
"""Check that processincomingmessage works with mailbox_name given"""
mailbox_name = 'foo_mailbox'
mailbox_name = "foo_mailbox"
with mock.patch('django_mailbox.management.commands.processincomingmessage.Command.handle') as handle:
with mock.patch(
"django_mailbox.management.commands.processincomingmessage.Command.handle"
) as handle:
handle.return_value = None
call_command('processincomingmessage', mailbox_name)
call_command("processincomingmessage", mailbox_name)
args, kwargs = handle.call_args
try:
self.assertEqual(kwargs['mailbox_name'], mailbox_name)
self.assertEqual(kwargs["mailbox_name"], mailbox_name)
except (AssertionError, KeyError):
# Handle Django 1.7
# It uses optparse instead of argparse, so instead of being
@ -55,11 +59,12 @@ class CommandsTestCase(TestCase):
# error, which means this test is worthless anyway
# For the "compatibility" versions, unexpected arguments aren't handled
# very well, and result in a TypeError
if (LooseVersion(django.get_version()) >= LooseVersion('1.8') and
LooseVersion(django.get_version()) < LooseVersion('1.10')):
if LooseVersion(django.get_version()) >= LooseVersion("1.8") and LooseVersion(
django.get_version()
) < LooseVersion("1.10"):
with self.assertRaises(TypeError):
call_command('processincomingmessage', 'foo_mailbox', 'invalid_arg')
call_command("processincomingmessage", "foo_mailbox", "invalid_arg")
# In 1.10 and later a proper CommandError should be raised
elif LooseVersion(django.get_version()) >= LooseVersion('1.10'):
elif LooseVersion(django.get_version()) >= LooseVersion("1.10"):
with self.assertRaises(CommandError):
call_command('processincomingmessage', 'foo_mailbox', 'invalid_arg')
call_command("processincomingmessage", "foo_mailbox", "invalid_arg")

View file

@ -1,44 +1,32 @@
from unittest import mock
from os.path import exists
from os import remove
from django.test.utils import override_settings
from django_mailbox.tests.base import EmailMessageTestCase, get_email_as_text
from django_mailbox.transports import ImapTransport, Pop3Transport
FAKE_UID_SEARCH_ANSWER = (
'OK',
"OK",
[
b'18 19 20 21 22 23 24 25 26 27 28 29 ' +
b'30 31 32 33 34 35 36 37 38 39 40 41 42 43 44'
]
b"18 19 20 21 22 23 24 25 26 27 28 29 "
+ b"30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
],
)
FAKE_UID_FETCH_SIZES = (
'OK',
[
b'1 (UID 18 RFC822.SIZE 58070000000)',
b'2 (UID 19 RFC822.SIZE 2593)'
]
"OK",
[b"1 (UID 18 RFC822.SIZE 58070000000)", b"2 (UID 19 RFC822.SIZE 2593)"],
)
FAKE_UID_FETCH_MSG = (
'OK',
"OK",
[
(
b'1 (UID 18 RFC822 {5807}',
get_email_as_text('generic_message.eml')
),
]
)
FAKE_UID_COPY_MSG = (
'OK',
[
b'[COPYUID 1 2 2] (Success)'
]
(b"1 (UID 18 RFC822 {5807}", get_email_as_text("generic_message.eml")),
],
)
FAKE_UID_COPY_MSG = ("OK", [b"[COPYUID 1 2 2] (Success)"])
FAKE_LIST_ARCHIVE_FOLDERS_ANSWERS = (
'OK',
[
b'(\\HasNoChildren \\All) "/" "[Gmail]/All Mail"'
]
"OK",
[b'(\\HasNoChildren \\All) "/" "[Gmail]/All Mail"'],
)
@ -47,14 +35,14 @@ class IMAPTestCase(EmailMessageTestCase):
def imap_server_uid_method(*args):
cmd = args[0]
arg2 = args[2]
if cmd == 'search':
if cmd == "search":
return FAKE_UID_SEARCH_ANSWER
if cmd == 'copy':
if cmd == "copy":
return FAKE_UID_COPY_MSG
if cmd == 'fetch':
if arg2 == '(RFC822.SIZE)':
if cmd == "fetch":
if arg2 == "(RFC822.SIZE)":
return FAKE_UID_FETCH_SIZES
if arg2 == '(RFC822)':
if arg2 == "(RFC822)":
return FAKE_UID_FETCH_MSG
def imap_server_list_method(pattern=None):
@ -69,39 +57,35 @@ class IMAPTestCase(EmailMessageTestCase):
class TestImapTransport(IMAPTestCase):
def setUp(self):
super().setUp()
self.arbitrary_hostname = 'one.two.three'
self.arbitrary_hostname = "one.two.three"
self.arbitrary_port = 100
self.ssl = False
self.transport = ImapTransport(
self.arbitrary_hostname,
self.arbitrary_port,
self.ssl
self.arbitrary_hostname, self.arbitrary_port, self.ssl
)
self.transport.server = self.imap_server
def test_get_email_message(self):
if exists("store.json"):
remove("store.json")
actual_messages = list(self.transport.get_message())
self.assertEqual(len(actual_messages), 27)
actual_message = actual_messages[0]
expected_message = self._get_email_object('generic_message.eml')
expected_message = self._get_email_object("generic_message.eml")
self.assertEqual(expected_message, actual_message)
class TestImapArchivedTransport(TestImapTransport):
def setUp(self):
super().setUp()
self.archive = 'Archive'
self.archive = "Archive"
self.transport = ImapTransport(
self.arbitrary_hostname,
self.arbitrary_port,
self.ssl,
self.archive
self.arbitrary_hostname, self.arbitrary_port, self.ssl, self.archive
)
self.transport.server = self.imap_server
class TestMaxSizeImapTransport(TestImapTransport):
@override_settings(DJANGO_MAILBOX_MAX_MESSAGE_SIZE=5807)
def setUp(self):
super().setUp()
@ -121,38 +105,40 @@ class TestMaxSizeImapTransport(TestImapTransport):
self.assertEqual(len(small_message_ids), 1)
def test_get_email_message(self):
if exists("store.json"):
remove("store.json")
actual_messages = list(self.transport.get_message())
self.assertEqual(len(actual_messages), 1)
actual_message = actual_messages[0]
expected_message = self._get_email_object('generic_message.eml')
expected_message = self._get_email_object("generic_message.eml")
self.assertEqual(expected_message, actual_message)
class TestPop3Transport(EmailMessageTestCase):
def setUp(self):
self.arbitrary_hostname = 'one.two.three'
self.arbitrary_hostname = "one.two.three"
self.arbitrary_port = 100
self.ssl = False
self.transport = Pop3Transport(
self.arbitrary_hostname,
self.arbitrary_port,
self.ssl
self.arbitrary_hostname, self.arbitrary_port, self.ssl
)
self.transport.server = None
super().setUp()
def test_get_email_message(self):
with mock.patch.object(self.transport, 'server') as server:
if exists("store.json"):
remove("store.json")
with mock.patch.object(self.transport, "server") as server:
# Consider this value arbitrary, the second parameter
# should have one entry per message in the inbox
server.list.return_value = [None, ['some_msg']]
server.list.return_value = [None, ["some_msg"]]
server.retr.return_value = [
'+OK message follows',
"+OK message follows",
[
line.encode('ascii')
for line in self._get_email_as_text(
'generic_message.eml'
).decode('ascii').split('\n')
line.encode("ascii")
for line in self._get_email_as_text("generic_message.eml")
.decode("ascii")
.split("\n")
],
10018, # Some arbitrary size, ideally matching the above
]
@ -162,6 +148,6 @@ class TestPop3Transport(EmailMessageTestCase):
self.assertEqual(len(actual_messages), 1)
actual_message = actual_messages[0]
expected_message = self._get_email_object('generic_message.eml')
expected_message = self._get_email_object("generic_message.eml")
self.assertEqual(expected_message, actual_message)

View file

@ -1,4 +1,4 @@
import sys
# import sys
from .base import EmailTransport

View file

@ -7,7 +7,6 @@ logger = logging.getLogger(__name__)
class GmailImapTransport(ImapTransport):
def connect(self, username, password):
# Try to use oauth2 first. It's much safer
try:
@ -28,30 +27,25 @@ class GmailImapTransport(ImapTransport):
AccessTokenNotFound,
)
except ImportError:
raise ValueError(
"Install python-social-auth to use oauth2 auth for gmail"
)
raise ValueError("Install python-social-auth to use oauth2 auth for gmail")
access_token = None
while access_token is None:
try:
access_token = get_google_access_token(username)
google_email_address = fetch_user_info(username)['email']
google_email_address = fetch_user_info(username)["email"]
except TypeError:
# This means that the google process took too long
# Trying again is the right thing to do
pass
except AccessTokenNotFound:
raise ValueError(
"No Token available in python-social-auth for %s" % (
username
)
"No Token available in python-social-auth for %s" % (username)
)
auth_string = 'user={}\1auth=Bearer {}\1\1'.format(
google_email_address,
access_token
auth_string = "user={}\1auth=Bearer {}\1\1".format(
google_email_address, access_token
)
self.server = self.transport(self.hostname, self.port)
self.server.authenticate('XOAUTH2', lambda x: auth_string)
self.server.authenticate("XOAUTH2", lambda x: auth_string)
self.server.select()

View file

@ -1,6 +1,7 @@
import imaplib
import logging
from os.path import exists
import json
from django.conf import settings
from .base import EmailTransport, MessageParseError
@ -18,28 +19,25 @@ logger = logging.getLogger(__name__)
class ImapTransport(EmailTransport):
def __init__(
self, hostname, port=None, ssl=False, tls=False,
archive='', folder=None,
self,
hostname,
port=None,
ssl=False,
tls=False,
archive="",
folder=None,
):
self.max_message_size = getattr(
settings,
'DJANGO_MAILBOX_MAX_MESSAGE_SIZE',
False
settings, "DJANGO_MAILBOX_MAX_MESSAGE_SIZE", False
)
self.integration_testing_subject = getattr(
settings,
'DJANGO_MAILBOX_INTEGRATION_TESTING_SUBJECT',
None
settings, "DJANGO_MAILBOX_INTEGRATION_TESTING_SUBJECT", None
)
self.delete_message_from_server = getattr(
settings,
'DJANGO_MAILBOX_DELETE_MESSAGE_FROM_SERVER',
True
settings, "DJANGO_MAILBOX_DELETE_MESSAGE_FROM_SERVER", True
)
self.delete_message_store = getattr(
settings,
'DJANGO_MAILBOX_DELETE_MESSAGE_STORE',
"/tmp/store.json"
settings, "DJANGO_MAILBOX_DELETE_MESSAGE_ID_STORE", "/tmp/store.json"
)
self.hostname = hostname
self.port = port
@ -68,13 +66,13 @@ class ImapTransport(EmailTransport):
def _get_all_message_ids(self):
# Fetch all the message uids
response, message_ids = self.server.uid('search', None, 'ALL')
response, message_ids = self.server.uid("search", None, "ALL")
message_id_string = message_ids[0].strip()
# Usually `message_id_string` will be a list of space-separated
# ids; we must make sure that it isn't an empty string before
# splitting into individual UIDs.
if message_id_string:
return message_id_string.decode().split(' ')
return message_id_string.decode().split(" ")
return []
def _get_small_message_ids(self, message_ids):
@ -83,23 +81,17 @@ class ImapTransport(EmailTransport):
# limit
safe_message_ids = []
status, data = self.server.uid(
'fetch',
','.join(message_ids),
'(RFC822.SIZE)'
)
status, data = self.server.uid("fetch", ",".join(message_ids), "(RFC822.SIZE)")
for each_msg in data:
each_msg = each_msg.decode()
try:
uid = each_msg.split(' ')[2]
size = each_msg.split(' ')[4].rstrip(')')
uid = each_msg.split(" ")[2]
size = each_msg.split(" ")[4].rstrip(")")
if int(size) <= int(self.max_message_size):
safe_message_ids.append(uid)
except ValueError as e:
logger.warning(
"ValueError: {} working on {}".format(e, each_msg[0])
)
logger.warning("ValueError: {} working on {}".format(e, each_msg[0]))
pass
return safe_message_ids
@ -120,9 +112,9 @@ class ImapTransport(EmailTransport):
self.server.create(self.archive)
# PoC of alternative method of storing email
if not self.delete_from_server:
if not self.delete_message_from_server:
j = {"uids": []}
if os.path.exists("store.json"):
if exists("store.json"):
with open("store.json", "r") as f:
j = json.load(f)
else:
@ -130,10 +122,9 @@ class ImapTransport(EmailTransport):
json.dump(j, f)
# PoC of alternative method of storing email
for uid in message_ids:
# PoC of alternative method of storing email
if not self.delete_from_server:
if not self.delete_message_from_server:
if uid in j["uids"]:
continue
else:
@ -143,7 +134,7 @@ class ImapTransport(EmailTransport):
# PoC of alternative method of storing email
try:
typ, msg_contents = self.server.uid('fetch', uid, '(RFC822)')
typ, msg_contents = self.server.uid("fetch", uid, "(RFC822)")
if not msg_contents:
continue
try:
@ -162,8 +153,9 @@ class ImapTransport(EmailTransport):
continue
if self.archive:
self.server.uid('copy', uid, self.archive)
self.delete_message_from_server:
self.server.uid('store', uid, "+FLAGS", "(\\Deleted)")
self.server.uid("copy", uid, self.archive)
if self.delete_message_from_server:
self.server.uid("store", uid, "+FLAGS", "(\\Deleted)")
self.server.expunge()
return

View file

@ -22,15 +22,13 @@ class Pop3Transport(EmailTransport):
self.server.pass_(password)
def get_message_body(self, message_lines):
return bytes('\r\n', 'ascii').join(message_lines)
return bytes("\r\n", "ascii").join(message_lines)
def get_message(self, condition=None):
message_count = len(self.server.list()[1])
for i in range(message_count):
try:
msg_contents = self.get_message_body(
self.server.retr(i + 1)[1]
)
msg_contents = self.get_message_body(self.server.retr(i + 1)[1])
message = self.get_email_from_bytes(msg_contents)
if condition and not condition(message):

View file

@ -11,127 +11,112 @@ logger = logging.getLogger(__name__)
def get_settings():
return {
'strip_unallowed_mimetypes': getattr(
settings,
'DJANGO_MAILBOX_STRIP_UNALLOWED_MIMETYPES',
False
"strip_unallowed_mimetypes": getattr(
settings, "DJANGO_MAILBOX_STRIP_UNALLOWED_MIMETYPES", False
),
'allowed_mimetypes': getattr(
settings,
'DJANGO_MAILBOX_ALLOWED_MIMETYPES',
[
'text/plain',
'text/html'
]
"allowed_mimetypes": getattr(
settings, "DJANGO_MAILBOX_ALLOWED_MIMETYPES", ["text/plain", "text/html"]
),
'text_stored_mimetypes': getattr(
"text_stored_mimetypes": getattr(
settings,
'DJANGO_MAILBOX_TEXT_STORED_MIMETYPES',
[
'text/plain',
'text/html'
]
"DJANGO_MAILBOX_TEXT_STORED_MIMETYPES",
["text/plain", "text/html"],
),
'altered_message_header': getattr(
"altered_message_header": getattr(
settings,
'DJANGO_MAILBOX_ALTERED_MESSAGE_HEADER',
'X-Django-Mailbox-Altered-Message'
"DJANGO_MAILBOX_ALTERED_MESSAGE_HEADER",
"X-Django-Mailbox-Altered-Message",
),
'attachment_interpolation_header': getattr(
"attachment_interpolation_header": getattr(
settings,
'DJANGO_MAILBOX_ATTACHMENT_INTERPOLATION_HEADER',
'X-Django-Mailbox-Interpolate-Attachment'
"DJANGO_MAILBOX_ATTACHMENT_INTERPOLATION_HEADER",
"X-Django-Mailbox-Interpolate-Attachment",
),
'attachment_upload_to': getattr(
"attachment_upload_to": getattr(
settings,
'DJANGO_MAILBOX_ATTACHMENT_UPLOAD_TO',
'mailbox_attachments/%Y/%m/%d/'
"DJANGO_MAILBOX_ATTACHMENT_UPLOAD_TO",
"mailbox_attachments/%Y/%m/%d/",
),
'store_original_message': getattr(
settings,
'DJANGO_MAILBOX_STORE_ORIGINAL_MESSAGE',
False
"store_original_message": getattr(
settings, "DJANGO_MAILBOX_STORE_ORIGINAL_MESSAGE", False
),
'compress_original_message': getattr(
settings,
'DJANGO_MAILBOX_COMPRESS_ORIGINAL_MESSAGE',
False
"compress_original_message": getattr(
settings, "DJANGO_MAILBOX_COMPRESS_ORIGINAL_MESSAGE", False
),
'original_message_compression': getattr(
settings,
'DJANGO_MAILBOX_ORIGINAL_MESSAGE_COMPRESSION',
6
"original_message_compression": getattr(
settings, "DJANGO_MAILBOX_ORIGINAL_MESSAGE_COMPRESSION", 6
),
'default_charset': getattr(
"default_charset": getattr(
settings,
'DJANGO_MAILBOX_default_charset',
'iso8859-1',
)
"DJANGO_MAILBOX_default_charset",
"iso8859-1",
),
}
def convert_header_to_unicode(header):
default_charset = get_settings()['default_charset']
default_charset = get_settings()["default_charset"]
def _decode(value, encoding):
if isinstance(value, str):
return value
if not encoding or encoding == 'unknown-8bit':
if not encoding or encoding == "unknown-8bit":
encoding = default_charset
return value.decode(encoding, 'replace')
return value.decode(encoding, "replace")
try:
return ''.join(
return "".join(
[
(
_decode(bytestr, encoding)
) for bytestr, encoding in email.header.decode_header(header)
(_decode(bytestr, encoding))
for bytestr, encoding in email.header.decode_header(header)
]
)
except UnicodeDecodeError:
logger.exception(
'Errors encountered decoding header %s into encoding %s.',
"Errors encountered decoding header %s into encoding %s.",
header,
default_charset,
)
return header.decode(default_charset, 'replace')
return header.decode(default_charset, "replace")
def get_body_from_message(message, maintype, subtype):
"""
Fetchs the body message matching main/sub content type.
"""
body = ''
body = ""
for part in message.walk():
if part.get('content-disposition', '').startswith('attachment;'):
if part.get("content-disposition", "").startswith("attachment;"):
continue
if part.get_content_maintype() == maintype and \
part.get_content_subtype() == subtype:
if (
part.get_content_maintype() == maintype
and part.get_content_subtype() == subtype
):
charset = part.get_content_charset()
this_part = part.get_payload(decode=True)
if charset:
try:
this_part = this_part.decode(charset, 'replace')
this_part = this_part.decode(charset, "replace")
except LookupError:
this_part = this_part.decode('ascii', 'replace')
this_part = this_part.decode("ascii", "replace")
logger.warning(
'Unknown encoding %s encountered while decoding '
'text payload. Interpreting as ASCII with '
'replacement, but some data may not be '
'represented as the sender intended.',
charset
"Unknown encoding %s encountered while decoding "
"text payload. Interpreting as ASCII with "
"replacement, but some data may not be "
"represented as the sender intended.",
charset,
)
except ValueError:
this_part = this_part.decode('ascii', 'replace')
this_part = this_part.decode("ascii", "replace")
logger.warning(
'Error encountered while decoding text '
'payload from an incorrectly-constructed '
'e-mail; payload was converted to ASCII with '
'replacement, but some data may not be '
'represented as the sender intended.'
"Error encountered while decoding text "
"payload from an incorrectly-constructed "
"e-mail; payload was converted to ASCII with "
"replacement, but some data may not be "
"represented as the sender intended."
)
else:
this_part = this_part.decode('ascii', 'replace')
this_part = this_part.decode("ascii", "replace")
body += this_part
@ -141,8 +126,8 @@ def get_body_from_message(message, maintype, subtype):
def get_attachment_save_path(instance, filename):
settings = get_settings()
path = settings['attachment_upload_to']
if '%' in path:
path = settings["attachment_upload_to"]
if "%" in path:
path = datetime.datetime.utcnow().strftime(path)
return os.path.join(

View file

@ -24,32 +24,32 @@ import sys, os
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = 'django-mailbox'
copyright = '2020, Adam Coddington'
project = "django-mailbox"
copyright = "2020, Adam Coddington"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '3.3'
version = "3.3"
# The full version, including alpha/beta/rc tags.
release = '3.3'
release = "3.3"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -63,7 +63,7 @@ release = '3.3'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
@ -80,7 +80,7 @@ exclude_patterns = ['_build']
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
@ -90,7 +90,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = "default"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@ -163,7 +163,7 @@ html_theme = 'default'
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'django-mailboxdoc'
htmlhelp_basename = "django-mailboxdoc"
# -- Options for LaTeX output --------------------------------------------------
@ -171,10 +171,8 @@ htmlhelp_basename = 'django-mailboxdoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
@ -182,8 +180,13 @@ latex_elements = {
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'django-mailbox.tex', 'django-mailbox Documentation',
'Adam Coddington', 'manual'),
(
"index",
"django-mailbox.tex",
"django-mailbox Documentation",
"Adam Coddington",
"manual",
),
]
# The name of an image file (relative to this directory) to place at the top of
@ -212,8 +215,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'django-mailbox', 'django-mailbox Documentation',
['Adam Coddington'], 1)
("index", "django-mailbox", "django-mailbox Documentation", ["Adam Coddington"], 1)
]
# If true, show URL addresses after external links.
@ -226,9 +228,15 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'django-mailbox', 'django-mailbox Documentation',
'Adam Coddington', 'django-mailbox', 'One line description of project.',
'Miscellaneous'),
(
"index",
"django-mailbox",
"django-mailbox Documentation",
"Adam Coddington",
"django-mailbox",
"One line description of project.",
"Miscellaneous",
),
]
# Documents to append as an appendix to all manuals.
@ -240,15 +248,21 @@ texinfo_documents = [
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath(".."))
import inspect
import django
from django.utils.html import strip_tags
from django.utils.encoding import force_text
from django.conf import settings
settings.configure(INSTALLED_APPS=['django_mailbox', ])
settings.configure(
INSTALLED_APPS=[
"django_mailbox",
]
)
django.setup()
def process_docstring(app, what, name, obj, options, lines):
# Source: https://gist.github.com/abulka/48b54ea4cbc7eb014308
# This causes import errors if left outside the function
@ -261,7 +275,7 @@ def process_docstring(app, what, name, obj, options, lines):
for field in fields:
# Skip ManyToOneRel and ManyToManyRel fields which have no 'verbose_name' or 'help_text'
if not hasattr(field, 'verbose_name'):
if not hasattr(field, "verbose_name"):
continue
# Decode and strip any html out of the field's help text
@ -274,22 +288,27 @@ def process_docstring(app, what, name, obj, options, lines):
if help_text:
# Add the model field to the end of the docstring as a param
# using the help text as the description
lines.append(':param {}: {}'.format(field.attname, help_text))
lines.append(":param {}: {}".format(field.attname, help_text))
else:
# Add the model field to the end of the docstring as a param
# using the verbose name as the description
lines.append(':param {}: {}'.format(field.attname, verbose_name))
lines.append(":param {}: {}".format(field.attname, verbose_name))
# Add the field's type to the docstring
if isinstance(field, models.ForeignKey):
to = field.related_model
lines.append(':type {}: {} to :class:`~{}.{}`'.format(field.attname, type(field).__name__, to.__module__, to.__name__))
lines.append(
":type {}: {} to :class:`~{}.{}`".format(
field.attname, type(field).__name__, to.__module__, to.__name__
)
)
else:
lines.append(':type {}: {}'.format(field.attname, type(field).__name__))
lines.append(":type {}: {}".format(field.attname, type(field).__name__))
# Return the extended docstring
return lines
def setup(app):
# Register the docstring processor with sphinx
app.connect('autodoc-process-docstring', process_docstring)
app.connect("autodoc-process-docstring", process_docstring)

View file

@ -11,6 +11,8 @@ Django = "^3.1.6"
[tool.poetry.dev-dependencies]
pytest = "^6.2.2"
pytest-django = "^4.1.0"
flake8 = "^3.8.4"
black = "^20.8b1"
[build-system]
requires = ["poetry-core>=1.0.0"]

View file

@ -1,29 +1,38 @@
.. image:: https://travis-ci.org/coddingtonbear/django-mailbox.png?branch=master
:target: https://travis-ci.org/coddingtonbear/django-mailbox
.. image:: https://badge.fury.io/py/django-mailbox.png
:target: http://badge.fury.io/py/django-mailbox
.. image:: https://pypip.in/d/django-mailbox/badge.png
:target: https://pypi.python.org/pypi/django-mailbox
Django Mailbox2
===============
This is a modified version of the original.
Easily ingest messages from POP3, IMAP, or local mailboxes into your Django application.
This is a modified version that has extra features. I think I need to make it better.
This app allows you to either ingest e-mail content from common e-mail services (as long as the service provides POP3 or IMAP support),
or directly receive e-mail messages from ``stdin`` (for locally processing messages from Postfix or Exim4).
These ingested messages will be stored in the database in Django models and you can process their content at will,
or -- if you're in a hurry -- by using a signal receiver.
### Usage
1. poetry add django-mailbox
2. After you have installed the package, add django_mailbox to the INSTALLED_APPS setting in your projects settings.py file.
3. From your project folder, run python manage.py migrate django_mailbox to create the required database tables.
4. Head to your projects Django Admin and create a mailbox to consume.
a. if you do not want it to delete the messages on the server add these to settings.py
set DJANGO_MAILBOX_DELETE_MESSAGE_FROM_SERVER to false
set DJANGO_MAILBOX_DELETE_MESSAGE_ID_STORE to /path/to/messageid_store.json
5. python manage.py getmail
- Documentation for django-mailbox is available on
`ReadTheDocs <http://django-mailbox.readthedocs.org/>`_.
- Please post issues on
`Github <http://github.com/coddingtonbear/django-mailbox/issues>`_.
- Test status available on
`Travis-CI <https://travis-ci.org/coddingtonbear/django-mailbox>`_.
.. image:: https://badges.gitter.im/Join%20Chat.svg
:alt: Join the chat at https://gitter.im/coddingtonbear/django-mailbox
:target: https://gitter.im/coddingtonbear/django-mailbox?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge

View file

@ -1,4 +0,0 @@
[pytest]
norecursedirs=env docs lib .eggs
DJANGO_SETTINGS_MODULE=django_mailbox.tests.settings
addopts = --tb=short -rxs

View file

@ -1,60 +0,0 @@
from setuptools import find_packages, setup
from django_mailbox import __version__ as version_string
tests_require = [
'django',
'mock',
'unittest2',
]
gmail_oauth2_require = [
'python-social-auth',
]
setup(
name='django-mailbox',
version=version_string,
url='http://github.com/coddingtonbear/django-mailbox/',
description=(
'Import mail from POP3, IMAP, local mailboxes or directly from '
'Postfix or Exim4 into your Django application automatically.'
),
license='MIT',
author='Adam Coddington',
author_email='me@adamcoddington.net',
extras_require={
'gmail-oauth2': gmail_oauth2_require
},
python_requires=">=3",
classifiers=[
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Framework :: Django',
'Framework :: Django :: 1.11',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'Framework :: Django :: 2.2',
'Framework :: Django :: 3.0',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Topic :: Communications :: Email',
'Topic :: Communications :: Email :: Post-Office',
'Topic :: Communications :: Email :: Post-Office :: IMAP',
'Topic :: Communications :: Email :: Post-Office :: POP3',
'Topic :: Communications :: Email :: Email Clients (MUA)',
],
packages=find_packages(),
include_package_data=True,
install_requires=[
'six>=1.6.1'
]
)