diff --git a/README.md b/README.md
index 27416d7..8614ac7 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,32 @@
-# Open Trashmail
-Open source / selfhostable trashmail solution
+
+
+
+
+
+Open Trashmail
+
+
+
+![](https://img.shields.io/badge/php-7.1%2B-brightgreen.svg)
+![](https://img.shields.io/badge/python-2.7%2B-brightgreen.svg)
+[![Apache License](https://img.shields.io/badge/license-Apache-blue.svg?style=flat)](https://github.com/HaschekSolutions/opentrashmail/blob/master/LICENSE)
+[![HitCount](http://hits.dwyl.io/HaschekSolutions/opentrashmail.svg)](http://hits.dwyl.io/HaschekSolutions/opentrashmail)
+[![](https://img.shields.io/github/stars/HaschekSolutions/opentrashmail.svg?label=Stars&style=social)](https://github.com/HaschekSolutions/opentrashmail)
+
+#### Host your own `trashmail` solution to use with your own domains or subdomains
+
+
+
+# Roadmap
+- [x] Mailserver
+ - [x] Storing received mails in JSON
+ - [x] Storing file attachments
+- [ ] Web interface
+ - [ ] Choose email
+ - [ ] Get random email address
+ - [ ] Download attachments in a safe way
+- [ ] Customization options
+- [ ] Docker files and config
# Features
- Python powered mail server that works out of the box for any domain
diff --git a/python/mailserver.py b/python/mailserver.py
index e6fb2d8..3b75aa0 100644
--- a/python/mailserver.py
+++ b/python/mailserver.py
@@ -1,24 +1,118 @@
import smtpd
import asyncore
-import uuid
+import logging
+import email
+from email.header import decode_header
+from email.Utils import parseaddr
+import requests
import time
import os, sys
import json
-class CustomSMTPServer(smtpd.SMTPServer):
- def process_message(self, peer, mailfrom, rcpttos, data):
- print 'Receiving message from:', peer
- print 'Message addressed from:', mailfrom
- print 'Message addressed to :', rcpttos
- print 'Message length :', len(data)
- print "----------"
- for email in rcpttos:
- if not os.path.exists("../data/"+email):
- os.mkdir( "../data/"+email, 0755 )
- with open("../data/"+email+"/"+str(int(round(time.time() * 1000)))+".json", "w") as outfile:
- json.dump({'sender_ip':peer[0],'from':mailfrom,'rcpts':rcpttos,'data':data}, outfile)
-
- return
-server = CustomSMTPServer(('0.0.0.0', 25), None)
+logger = logging.getLogger(__name__)
-asyncore.loop()
\ No newline at end of file
+class CustomSMTPServer(smtpd.SMTPServer):
+ def process_message(self, peer, mailfrom, rcpttos, data):
+ try:
+ mailfrom = parseaddr(mailfrom)[1]
+ logger.debug('Receiving message from: %s:%d' % peer)
+ logger.debug('Message addressed from: %s' % mailfrom)
+ logger.debug('Message addressed to: %s' % str(rcpttos))
+
+
+
+ msg = email.message_from_string(data)
+ subject = ''
+ for encoded_string, charset in decode_header(msg.get('Subject')):
+ try:
+ if charset is not None:
+ subject += encoded_string.decode(charset)
+ else:
+ subject += encoded_string
+ except:
+ logger.exception('Error reading part of subject: %s charset %s' %
+ (encoded_string, charset))
+
+ logger.debug('Subject: %s' % subject)
+
+ text_parts = []
+ attachments = {}
+
+ #logger.debug('Headers: %s' % msg.items())
+
+ # YOU CAN DO SOME SECURITY CONTROLS HERE
+ #if (not mailfrom.endswith("@hankenfeld.at") or
+ # not msg.get('Mail-Header') == 'expected value'):
+ # raise Exception("Email not trusted")
+
+ # loop on the email parts
+ for part in msg.walk():
+ if part.get_content_maintype() == 'multipart':
+ continue
+
+ c_type = part.get_content_type()
+ c_disp = part.get('Content-Disposition')
+
+ # text parts will be appended to text_parts
+ if c_type == 'text/plain' and c_disp == None:
+ text_parts.append(part.get_payload(decode=True).strip())
+ # ignore html part
+ elif c_type == 'text/html':
+ continue
+ # attachments will be sent as files in the POST request
+ else:
+ filename = part.get_filename()
+ filecontent = part.get_payload(decode=True)
+ if filecontent is not None:
+ if filename is None:
+ filename = 'untitled'
+ attachments['file%d' % len(attachments)] = (filename,
+ filecontent)
+
+ body = '\n'.join(text_parts)
+
+ except:
+ logger.exception('Error reading incoming email')
+ else:
+ # this data will be sent as POST data
+ edata = {
+ 'subject': subject,
+ 'body': body,
+ 'from': mailfrom,
+ 'attachments':[]
+ }
+ savedata = {'sender_ip':peer[0],'from':mailfrom,'rcpts':rcpttos,'raw':data,'parsed':edata}
+
+ filenamebase = str(int(round(time.time() * 1000)))
+
+ for em in rcpttos:
+ if not os.path.exists("../data/"+em):
+ os.mkdir( "../data/"+em, 0755 )
+
+ #same attachments if any
+ for att in attachments:
+ if not os.path.exists("../data/"+em+"/attachments"):
+ os.mkdir( "../data/"+em+"/attachments", 0755 )
+ attd = attachments[att]
+ file = open("../data/"+em+"/attachments/"+filenamebase+"-"+attd[0], 'wb')
+ file.write(attd[1])
+ file.close()
+ edata["attachments"].append(filenamebase+"-"+attd[0])
+
+ # save actual json data
+ with open("../data/"+em+"/"+filenamebase+".json", "w") as outfile:
+ json.dump(savedata, outfile)
+
+ #print edata
+ return
+
+if __name__ == '__main__':
+ ch = logging.StreamHandler()
+ ch.setLevel(logging.DEBUG)
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ ch.setFormatter(formatter)
+ logger.setLevel(logging.DEBUG)
+ logger.addHandler(ch)
+
+ server = CustomSMTPServer(('0.0.0.0', 2525), None) # use your public IP here
+ asyncore.loop()
\ No newline at end of file