mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Added support for a shared secret in email
This commit is contained in:
		| @@ -90,13 +90,16 @@ So, with all that in mind, here's what you do to get it running: | ||||
|    folder in an existing email box and note the path to that folder. | ||||
| 2. In ``settings.py`` set all of the appropriate values in ``MAIL_CONSUMPTION``. | ||||
|    If you decided to use a subfolder of an existing account, then make sure you | ||||
|    set ``INBOX`` accordingly here. | ||||
|    set ``INBOX`` accordingly here.  You also have to set the | ||||
|    ``UPLOAD_SHARED_SECRET`` to something you can remember 'cause you'll have to | ||||
|    include that in every email you send. | ||||
| 3. Restart the :ref:`consumer <utilities-consumer>`.  The consumer will check | ||||
|    the configured email account every 10 minutes for something new and pull down | ||||
|    whatever it finds. | ||||
| 4. Send yourself an email!  Note that the subject is treated as the file name, | ||||
|    so if you set the subject to ``Sender - Title - tag,tag,tag``, you'll get | ||||
|    what you expect. | ||||
|    what you expect.  Also, you must include the aforementioned secret string in | ||||
|    every email so the fetcher knows that it's safe to import. | ||||
| 5. After a few minutes, the consumer will poll your mailbox, pull down the | ||||
|    message, and place the attachment in the consumption directory with the | ||||
|    appropriate name.  A few minutes later, the consumer will import it like any | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| import datetime | ||||
| import email | ||||
| import imaplib | ||||
| import os | ||||
| import re | ||||
| import time | ||||
|  | ||||
| from base64 import b64decode | ||||
| from email import policy | ||||
| from email.parser import BytesParser | ||||
| from dateutil import parser | ||||
|  | ||||
| from django.conf import settings | ||||
| @@ -29,14 +30,7 @@ class Message(Renderable): | ||||
|     and n attachments, and that we don't care about the message body. | ||||
|     """ | ||||
|  | ||||
|     def _set_time(self, message): | ||||
|         self.time = datetime.datetime.now() | ||||
|         message_time = message.get("Date") | ||||
|         if message_time: | ||||
|             try: | ||||
|                 self.time = parser.parse(message_time) | ||||
|             except (ValueError, AttributeError): | ||||
|                 pass  # We assume that "now" is ok | ||||
|     SECRET = settings.UPLOAD_SHARED_SECRET | ||||
|  | ||||
|     def __init__(self, data, verbosity=1): | ||||
|         """ | ||||
| @@ -50,17 +44,15 @@ class Message(Renderable): | ||||
|         self.time = None | ||||
|         self.attachment = None | ||||
|  | ||||
|         message = email.message_from_bytes(data) | ||||
|         self.subject = message.get("Subject").replace("\r\n", "") | ||||
|         message = BytesParser(policy=policy.default).parsebytes(data) | ||||
|         self.subject = str(message["Subject"]).replace("\r\n", "") | ||||
|         self.body = str(message.get_body()) | ||||
|  | ||||
|         self.check_subject() | ||||
|         self.check_body() | ||||
|  | ||||
|         self._set_time(message) | ||||
|  | ||||
|         if self.subject is None: | ||||
|             raise InvalidMessageError("Message does not have a subject") | ||||
|         if not Sender.SAFE_REGEX.match(self.subject): | ||||
|             raise InvalidMessageError("Message subject is unsafe: {}".format( | ||||
|                 self.subject)) | ||||
|  | ||||
|         self._render('Fetching email: "{}"'.format(self.subject), 1) | ||||
|  | ||||
|         attachments = [] | ||||
| @@ -94,6 +86,26 @@ class Message(Renderable): | ||||
|     def __bool__(self): | ||||
|         return bool(self.attachment) | ||||
|  | ||||
|     def check_subject(self): | ||||
|         if self.subject is None: | ||||
|             raise InvalidMessageError("Message does not have a subject") | ||||
|         if not Sender.SAFE_REGEX.match(self.subject): | ||||
|             raise InvalidMessageError("Message subject is unsafe: {}".format( | ||||
|                 self.subject)) | ||||
|  | ||||
|     def check_body(self): | ||||
|         if self.SECRET not in self.body: | ||||
|             raise InvalidMessageError("The secret wasn't in the body") | ||||
|  | ||||
|     def _set_time(self, message): | ||||
|         self.time = datetime.datetime.now() | ||||
|         message_time = message.get("Date") | ||||
|         if message_time: | ||||
|             try: | ||||
|                 self.time = parser.parse(message_time) | ||||
|             except (ValueError, AttributeError): | ||||
|                 pass  # We assume that "now" is ok | ||||
|  | ||||
|     @property | ||||
|     def file_name(self): | ||||
|         return "{}.{}".format(self.subject, self.attachment.suffix) | ||||
|   | ||||
| @@ -38,7 +38,7 @@ This is a multi-part message in MIME format. | ||||
| Content-Type: text/plain; charset=utf-8 | ||||
| Content-Transfer-Encoding: 7bit | ||||
|  | ||||
| This is the test body. | ||||
| The secret word is "paperless" :-) | ||||
|  | ||||
| --------------090701020702030809070008 | ||||
| Content-Type: application/pdf; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Daniel Quinn
					Daniel Quinn