OPDATERING 29. maj 2019: Dette program virker ikke længere. Prøv dette i stedet.
Der er mange, der har fået den idé, automatisk at videresende beskeder i E-boks til en anden mailadresse eller gemme dem på computeren. Videresendelse kan også gøres i E-boks selv, men kun manuelt og en besked ad gangen. Her er nogle projekter:
- MinEBoks og MinBoks af Lars Pehrsson: Windows Service og program
- E-boks-mailer by Christian Panton: Python-program, men dur ikke længere pga. ændringer i E-boks
- Net-Eboks by Dmitry Karasik: Perl-program
- Postboks af Ole Gam: Til Mac
Jeg kan kun finde ud af Python, og ved hvordan jeg sætter et job op på min webserver, der kan gøre Python-programmer regelmæssigt (det skulle jeg nemlig bruge til https://wallnot.dk).
Så – med kæmpe hjælp fra koden til Net-Eboks af Dmitry Karasik – har jeg skrevet et Python-program, der videresender nye beskeder i E-boks til min mail.
Programmet fungerer, men det er ikke gennemtestet, og tager ikke højde for fejl, fx. at brugeren indtaster forkerte oplysninger i programmet. Så det er nok en god idé også at logge ind på E-boks en gang imellem og lige se at alt bliver hentet og videresendt.
Du er velkommen til at bruge programmet, videreudvikle, og hvad du ellers kan finde på.
# -*- coding: utf-8 -*-
# Author: Morten Helmstedt. E-mail: helmstedt@gmail.com.
# Based on https://github.com/dk/Net-Eboks perl API for eboks.dk by Dmitry Karasik. Thanks!
""" This program logs on to e-boks.dk and takes new messages and sends them
to an e-mail. It requires mobile app login for e-boks (see http://www.e-boks.dk/help.aspx?pageid=db5a89a1-8530-418a-90e9-ff7f0713784a for
how to create). It also requires access to a secure (SSL) SMTP server and mail
account for sending e-mails. """
# Necessary modules
from datetime import datetime # Current date and time
import requests # Communicating with E-boks
import hashlib # Hash configuration for challenge/logon
import xml.etree.ElementTree as ET # Parse E-boks XML responses
import smtplib # Sending e-mails
from email.mime.multipart import MIMEMultipart # Creating multipart e-mails
from email.mime.text import MIMEText # Attaching text to e-mails
from email.mime.application import MIMEApplication # Attaching pdf to e-mails
from email.mime.image import MIMEImage # Attaching images to e-mails
from email.utils import formataddr # Used for correct encoding of senders with special characters in name (e.g. Københavns Kommune)
import chardet # Text message character set detection
import time # Pause between e-mails sent
# Configuration data
data = {
'emailserver': '', # Your mail server hostname: host.server.dk
'emailserverport': , # Mail server port, e.g. 465
'emailusername': '', # Sender mail account username
'emailpassword': '', # Sender mail account password
'emailfrom': '', # Sender e-mail, e.g. trump@usa.gov
'emailto': '', # Recipient e-mail, e.g. hillary@clinton.net
'cpr': '', # CPR number (no hyphens), e.g. 1234567890
'password': '', # E-boks mobile account password
'activation': '', # E-boks mobile account activation code
'numberofmessagesperfolder': '10', # Number of messages to request (10 is usually enough)
'unreadstatusvalue': "true", # Normally "true". If "false" also read messages are sent
'unreadmorethan': 0, # Normally 0, only unread messages are sent. If -1 all messages are sent
'sendemails': True, # If True, e-mails are sent, if False, they are not
'country': 'DK',
'type': 'P',
'deviceid': 'python-e-boks-000000000000',
'datetime': '',
'root': 'rest.e-boks.dk',
'nonce': '',
'sessionid': '',
'response': '3a1a51f235a8bd6bbc29b2caef986a1aeb77018d60ffdad9c5e31117e7b6ead3',
'uid': '',
'uname': '',
'challenge': ''
}
# Gets current date and time for E-boks challenge
now = datetime.now()
data['datetime'] = datetime.strftime(now, '%Y-%m-%d %H:%M:%SZ')
# Hashes parts of configuration data and sets challenge value to authenticate with E-boks
hashstring = data['activation']+":"+data['deviceid']+":"+data['type']+":"+data['cpr']+":"+data['country']+":"+data['password']+":"+data['datetime']
hashstringcoded = hashstring.encode('utf-8')
data['challenge'] = hashlib.sha256(hashstringcoded).hexdigest().encode('utf-8')
data['challenge'] = hashlib.sha256(data['challenge']).hexdigest()
# These functions are used to create sessionid, nonce and authstring values for communicating
# with E-boks throughout the program
def sessionid(authenticate):
sessionstart = authenticate.find('sessionid="')+len('sessionid="')
sessionend = authenticate.find('"', sessionstart)
data['sessionid'] = authenticate[sessionstart:sessionend]
def nonce(authenticate):
noncestart = authenticate.find('nonce="')+len('nonce="')
nonceend = authenticate.find('"', noncestart)
data['nonce'] = authenticate[noncestart:nonceend]
def createauthstring():
authstr = 'deviceid="' + data['deviceid'] + '",nonce="' + data['nonce'] + ',sessionid="' + data['sessionid'] + '",response="' + data['response'] + '"'
return authstr
# Logon to mail server
server = smtplib.SMTP_SSL(data['emailserver'], data['emailserverport'])
server.login(data['emailusername'], data['emailpassword'])
# First logon to e-boks
url = "https://" + data['root'] + "/mobile/1/xml.svc/en-gb/session"
content = '<Logon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:eboks:mobile:1.0.0"><User identity="' + data['cpr'] + '" identityType="' + data['type'] + '" nationality="' + data['country'] + '" pincode="' + data['password'] + '"/></Logon>'
authstr = 'logon ' + 'deviceid="' + data['deviceid']+ '",' + 'datetime="' + data['datetime'] + '",' + 'challenge="' + data['challenge'] + '"'
headers = {
'Content-Type': 'application/xml',
'Content-Length': str(len(content)),
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Accept-Encoding': 'gzip,deflate',
'Host': data['root'],
}
r = requests.put(url, headers=headers, data=content)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
sessionid(authenticate)
xml = ET.fromstring(r.text)
# Saves username and user id
data['uname'] = xml[0].attrib['name']
data['uid'] = xml[0].attrib['userId']
# Get folder data from e-boks
url = 'https://' + data['root'] + '/mobile/1/xml.svc/en-gb/' + data['uid'] + '/0/mail/folders'
authstr = createauthstring()
headers = {
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Host': data['root'],
}
r = requests.get(url, headers=headers)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
xml = ET.fromstring(r.text)
eboks_folders = xml
# Get folder id's and numbers of unread messages
for folder in eboks_folders:
folderid = folder.attrib['id']
unread = folder.attrib['unread']
# Get messages ONLY if any unread messages in folder
if int(unread) > data['unreadmorethan']: # Usually > 0. Can be changed to == 0 for debugging purposes
# Get list of messages
url = 'https://' + data['root'] + '/mobile/1/xml.svc/en-gb/' + data['uid'] + '/0/mail/folder/' + folderid
authstr = createauthstring()
headers = {
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Host': data['root'],
}
params = {
'skip': '0',
'take': data['numberofmessagesperfolder']
}
r = requests.get(url, headers=headers, params=params)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
xml = ET.fromstring(r.text)
eboks_messages = xml
i = 0
max = int(params['take']) - 1
while i <= max:
for child in eboks_messages:
messageid = child[i].attrib['id']
subject = child[i].attrib['name']
sender = child[i][0].text
unreadstatus = child[i].attrib['unread']
attachmentcount = child[i].attrib['attachmentsCount']
format = child[i].attrib['format'].lower()
received = child[i].attrib['receivedDateTime']
i += 1
# Get only messages that are unread
if unreadstatus == data['unreadstatusvalue']: # Usually true. Can be changed to false for debugging purposes
# Start e-mail
msg = MIMEMultipart()
msg['From'] = formataddr((sender, data['emailfrom']))
msg['To'] = data['emailto']
msg['Subject'] = "E-boks: " + subject
body = ""
# Get message (marks it as read)
url = 'https://' + data['root'] + '/mobile/1/xml.svc/en-gb/' + data['uid'] + '/0/mail/folder/' + folderid + '/message/' + messageid
authstr = createauthstring()
headers = {
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Host': data['root'],
}
r = requests.get(url, headers=headers)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
# Get primary message content
url = 'https://' + data['root'] + '/mobile/1/xml.svc/en-gb/' + data['uid'] + '/0/mail/folder/' + folderid + '/message/' + messageid + '/content'
authstr = createauthstring()
headers = {
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Host': data['root'],
}
r = requests.get(url, headers=headers)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
# Attach primary message content to e-mail
if format in ("txt","text","plain"):
characterset = chardet.detect(r.content)
r.encoding = characterset['encoding']
body = r.text
msg.attach(MIMEText(body, 'plain'))
elif format in ("html","htm"):
characterset = chardet.detect(r.content)
r.encoding = characterset['encoding']
body = r.text
msg.attach(MIMEText(body, 'html'))
elif format == "pdf":
filename = "".join([c for c in subject if c.isalpha() or c.isdigit() or c==' ']).rstrip() + "." + format
part = MIMEApplication(r.content)
part.add_header('Content-Disposition', 'attachment', filename = filename)
msg.attach(part)
elif format in ("gif","jpg","jpeg","tiff","tif","webp"):
filename = "".join([c for c in subject if c.isalpha() or c.isdigit() or c==' ']).rstrip() + "." + format
part = MIMEImage(r.content)
part.add_header('Content-Disposition', 'attachment', filename = filename)
msg.attach(part)
# Get attachment data if message has attachments
if int(attachmentcount) > 0:
url = 'https://' + data['root'] + '/mobile/1/xml.svc/en-gb/' + data['uid'] + '/0/mail/folder/' + folderid + '/message/' + messageid
authstr = createauthstring()
headers = {
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Host': data['root'],
}
r = requests.get(url, headers=headers)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
xml = ET.fromstring(r.text)
eboks_attachment = xml
# Gets if, name and format of attachment
for child in eboks_attachment:
for subtree in child:
attachmentid = subtree.attrib['id']
attachmenttitle = subtree.attrib['name']
attachmentformat = subtree.attrib['format']
# Gets the actual attachment
url = 'https://' + data['root'] + '/mobile/1/xml.svc/en-gb/' + data['uid'] + '/0/mail/folder/' + folderid + '/message/' + attachmentid + '/content'
authstr = createauthstring()
headers = {
'X-EBOKS-AUTHENTICATE': authstr,
'Accept': '*/*',
'Accept-Language': 'en-US',
'Host': data['root'],
}
r = requests.get(url, headers=headers)
authenticate = r.headers['X-EBOKS-AUTHENTICATE']
nonce(authenticate)
# Attach attachment to e-mail
if attachmentformat in ("txt","text","html","htm","plain"):
filename = "".join([c for c in attachmenttitle if c.isalpha() or c.isdigit() or c==' ']).rstrip() + "." + attachmentformat
r.encoding = "utf-8"
part = MIMEText(r.text)
part.add_header('Content-Disposition', 'attachment', filename = filename)
msg.attach(part)
elif attachmentformat == "pdf":
filename = "".join([c for c in attachmenttitle if c.isalpha() or c.isdigit() or c==' ']).rstrip() + "." + attachmentformat
part = MIMEApplication(r.content)
part.add_header('Content-Disposition', 'attachment', filename = filename)
msg.attach(part)
elif attachmentformat in ("gif","jpg","jpeg","tiff","tif","webp"):
filename = "".join([c for c in attachmenttitle if c.isalpha() or c.isdigit() or c==' ']).rstrip() + "." + attachmentformat
part = MIMEImage(r.content)
part.add_header('Content-Disposition', 'attachment', filename = filename)
msg.attach(part)
# Send e-mail
if data['sendemails'] == True:
print("sending")
msg.attach(MIMEText(body, 'plain'))
server.sendmail(data['emailfrom'], data['emailto'], msg.as_string())
time.sleep(2)