support also saving inline attachments
This commit is contained in:
parent
953351e8a8
commit
83dc4405bf
|
@ -30,7 +30,6 @@ Does not support different accounts.
|
|||
```
|
||||
4. Edit `/etc/secrets/imapviewer` with this content:
|
||||
```shell
|
||||
SQLITE3_DB=<path to your sqlite3 database>
|
||||
HTTP_AUTH_PASS=<your encoded password>
|
||||
EMAIL_ARCHIVE_ROOT=<archive root path>
|
||||
```
|
||||
|
|
|
@ -26,11 +26,15 @@ def main(args):
|
|||
logger.critical('Bad config file.')
|
||||
sys.exit(1)
|
||||
|
||||
save_inline_attachments = config.get('save_inline_attachments', False)
|
||||
if save_inline_attachments:
|
||||
logger.info('Saving inline attachments as well')
|
||||
|
||||
attachments_dir = Path(config['attachments_path'])
|
||||
attachments_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
database = EmailDatabase(Path(config['database_path']))
|
||||
mail = MailConnection(config['server'], config['username'], config['password'], attachments_dir)
|
||||
mail = MailConnection(config['server'], config['username'], config['password'], attachments_dir, save_inline_attachments=save_inline_attachments)
|
||||
mail.load_folders()
|
||||
|
||||
if config['server'] == 'imap.gmail.com':
|
||||
|
|
|
@ -5,6 +5,10 @@ password: password123
|
|||
database_path: emails.db
|
||||
attachments_path: attachments
|
||||
|
||||
# Should inline content be saved as well?
|
||||
This will result in images and other inline content being saved, not just attachments.
|
||||
save_inline_attachments: false
|
||||
|
||||
exclude_folders:
|
||||
- Trash
|
||||
- Drafts
|
||||
|
|
|
@ -33,10 +33,11 @@ class FileAttachmentEncoder(JSONEncoder):
|
|||
|
||||
|
||||
class MailConnection:
|
||||
def __init__(self, host: str, username: str, password: str, attachments_dir: Path):
|
||||
def __init__(self, host: str, username: str, password: str, attachments_dir: Path, save_inline_attachments: bool = False):
|
||||
self.mail = imaplib.IMAP4_SSL(host)
|
||||
self.mail.login(username, password)
|
||||
self.attachments_dir = attachments_dir.expanduser().absolute().resolve()
|
||||
self.save_inline_attachments = save_inline_attachments
|
||||
self.folder_structure = {}
|
||||
self.logger = logging.getLogger('iarchiver.mail_conn')
|
||||
self.logger.setLevel(logging.INFO)
|
||||
|
@ -102,7 +103,7 @@ class MailConnection:
|
|||
if email_message.is_multipart():
|
||||
for part in email_message.walk():
|
||||
content_disposition = str(part.get("Content-Disposition"))
|
||||
if "attachment" in content_disposition:
|
||||
if 'attachment' in content_disposition or (self.save_inline_attachments and 'inline' in content_disposition):
|
||||
filename = part.get_filename()
|
||||
if filename:
|
||||
# The filename of the file is the hash of its content, which should de-duplicate files.
|
||||
|
@ -119,7 +120,7 @@ class MailConnection:
|
|||
attachments.append(file_obj)
|
||||
raw_email_clean = email_message.as_string()
|
||||
return unix_timestamp, to_header, from_header, subject, raw_email_clean, attachments
|
||||
except Exception as e:
|
||||
except:
|
||||
self.logger.critical(traceback.format_exc())
|
||||
return
|
||||
|
||||
|
|
25
server.py
25
server.py
|
@ -6,13 +6,11 @@ from datetime import datetime
|
|||
from pathlib import Path
|
||||
|
||||
import magic
|
||||
from flask import Flask, render_template, send_from_directory
|
||||
from flask import Flask, render_template, send_from_directory, abort
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
if not os.environ.get('SQLITE3_DB'):
|
||||
raise Exception('SQLITE3_DB not set.')
|
||||
if not os.environ.get('HTTP_AUTH_PASS'):
|
||||
raise Exception('HTTP_AUTH_PASS not set.')
|
||||
if not os.environ.get('EMAIL_ARCHIVE_ROOT'):
|
||||
|
@ -50,6 +48,8 @@ def index():
|
|||
@auth.login_required
|
||||
def account(email_account):
|
||||
conn = get_db_connection(email_account)
|
||||
if not conn:
|
||||
abort(404)
|
||||
folders = conn.execute('SELECT name, table_name FROM folders_mapping').fetchall()
|
||||
syncs = conn.execute('SELECT * FROM syncs ORDER BY timestamp DESC').fetchall()
|
||||
conn.close()
|
||||
|
@ -63,11 +63,13 @@ def account(email_account):
|
|||
@auth.login_required
|
||||
def folder(email_account, table_name):
|
||||
conn = get_db_connection(email_account)
|
||||
if not conn:
|
||||
abort(404)
|
||||
emails = conn.execute(f'SELECT * FROM {table_name} ORDER BY timestamp DESC').fetchall()
|
||||
conn.close()
|
||||
emails = [dict_from_row(email) for email in emails]
|
||||
for email in emails:
|
||||
email['timestamp'] = datetime.fromtimestamp(email['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
||||
for item in emails:
|
||||
item['timestamp'] = datetime.fromtimestamp(item['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
||||
return render_template('folder.html', emails=emails, table_name=table_name, email_account=email_account)
|
||||
|
||||
|
||||
|
@ -75,6 +77,8 @@ def folder(email_account, table_name):
|
|||
@auth.login_required
|
||||
def email(email_account, table_name, id):
|
||||
conn = get_db_connection(email_account)
|
||||
if not conn:
|
||||
abort(404)
|
||||
email = dict_from_row(conn.execute(f'SELECT * FROM {table_name} WHERE id = ?', (id,)).fetchone())
|
||||
conn.close()
|
||||
email['timestamp'] = datetime.fromtimestamp(email['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
@ -87,15 +91,18 @@ def email(email_account, table_name, id):
|
|||
def download_file(email_account, filename):
|
||||
p = Path(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'attachments', filename)
|
||||
if not p.exists():
|
||||
return 404
|
||||
abort(404)
|
||||
mimetype = magic.from_file(str(p), mime=True)
|
||||
return send_from_directory(Path(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'attachments'), filename, mimetype=mimetype)
|
||||
|
||||
|
||||
def get_db_connection(email_account):
|
||||
conn = sqlite3.connect(os.path.join(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'emails.db'))
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
try:
|
||||
conn = sqlite3.connect(os.path.join(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'emails.db'))
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in New Issue