Jeg har tidligere skrevet om mit Python-program til at få beskeder fra E-boks sendt på mail.
Nu har E-boks opgraderet sikkerheden, sådan man skal bruge Nemid til at aktivere E-boks på sin mobiltelefon, inden man får lov til at læse E-boks uden brug af Nemid.
Derfor var jeg nødt til at fikse mit program.
Løsningen blev at
bruge Android-emulatoren NOX, installerede app’en, aktivere med nemid og bruge Charles til at overvåge internettrafikken. Derefter genbrugte jeg app’ens kommunikation med E-boks’ server i mit program.

I mit program kopierede jeg headeren og indholdet fra Charles ind min første kommunikation med E-boks (har redigeret noget ud):
content = '<?xml version="1.0" encoding="utf-8"?><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"><App version="3.6.1-MOBILEACCESS2.210" os="Android" osVersion="4.4.2" device="SM-G925F" /><User identity="[mit cpr-nummer]" identityType="P" nationality="DK" pincode="[mit password]" /></Logon>' authstr = 'logon deviceid="[en id-streng]", datetime="2019-05-29 06:25:51Z", challenge="[en meget lang streng]"'
Det færdige program
Hvis du ønsker at bruge det færdige program, skal du:
- Installere Nox (eller en anden Android-emulator)
- Installere Charles (eller et andet program til at overvåge internettrafik)
- Opsætte Nox til at bruge Charles’ IP som proxy-server
- Åbne op for at kunne se SSL-traffik i Charles
- Installere E-boks-app’en i Nox og aktivere app’en med dit nemid
- Starte E-boks-app’en igen og logge på med dit CPR-nummer og password og logge trafikken i Charles
- Kopiere “content” og “authstr” fra Charles (se skærmbillede)og sætte ind i programmet hvor der står hhv. content = ” og authstr = ”
Held og lykke!
# -*- 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 prior Nemid activation using the E-boks app, e.g. running the Nox emulator and a traffic monitor such as Charles. 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 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 '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': '2', # Use id from http traffic monitor 'datetime': '', 'root': 'rest.e-boks.dk', 'nonce': '', 'sessionid': '', 'response': '523b931af795698785df1eb85e8c10ea0687a46edb3a48468943f2d368fe725a', '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') # 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" # Use XML string from http traffic monitor content = '' # Use string from http traffic monitor authstr = '' 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().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().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().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().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().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)