Email decodierung

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
xdowner
User
Beiträge: 5
Registriert: Sonntag 17. Dezember 2017, 19:06

Hallo liebe Gemeinde.

Ich habe nicht so viel Ahnung von Python und bräuchte etwas Unterstützung. Ich habe ein Python script welches meinen Gmail account auf neue Emails checkt. Bei einer neuen Email decodiert das script den Text und druckt ihn über einen Thermodrucker aus. Man muss die Zeichen angeben von wo bis wo das script die decodierung startet und endet.

Code: Alles auswählen

def decode_email(msg_str):
    body = quopri.decodestring(msg_str) #decodes
    #body = body[0:] #start from character number...
    #body = body[:230] #end in character number...
Also er startet mit der decodierung bei Zeichen 0 und endet mit Zeichen 230. Mein Problem ist nun das die Emails (in meinem Fall sind das Online bestellungen) alle unterschiedlich lang sind. Wie definiere ich nun das er bei Zeichen 0 anfängt und bis unendlich bzw. die ganze Email decodiert ?

Wäre toll wenn mir einer von euch unter die Arme greifen kann. Ich finde dafür keine Lösung.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du so wie in deinem code-snippet gezeigt einfach nix machst, dann ist body die gesamte Mail. Insofern verstehe ich jetzt nicht, was da noch zu tun bleibt, da muesstest du schon etwas weiter ausholen, ggf. mit Beispieldaten und mehr Code.
xdowner
User
Beiträge: 5
Registriert: Sonntag 17. Dezember 2017, 19:06

Das ist der code den ich soweit für meine Bedürfnisse angepasst habe.

Code: Alles auswählen

##!/usr/bin/env python

# This script is based in the Adafruit Internet of Things Printer 2 and the Raspberry Pi email notifier.
# The script executes every X time a new email verification, it is something new it prints it. 
# Written by Adafruit Industries and modified by DAFR ELECTRONICS.  MIT license.
#
# MUST BE RUN AS ROOT (due to GPIO access)
#
# Required software includes Adafruit_Thermal, Python Imaging and PySerial
# libraries. Other libraries used are part of stock Python install.
#
# Original code can be found here:
#https://github.com/adafruit/Python-Thermal-Printer
#https://learn.adafruit.com/raspberry-pi-e-mail-notifier-using-leds/overview

#Not all of these are neccesary, but maybe helpful.  
from imapclient import IMAPClient
import time
import RPi.GPIO as GPIO
from Adafruit_Thermal import *
from neopixel import *
import Image
import subprocess
import quopri
import string
import re

# LED strip configuration:
LED_COUNT      = 12      # Number of LED pixels.
LED_PIN        = 18      # GPIO pin connected to the pixels (18 uses PWM!).
#LED_PIN        = 10      # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ    = 800000  # LED signal frequency in hertz (usually 800khz)
LED_DMA        = 5       # DMA channel to use for generating signal (try 5)
LED_BRIGHTNESS = 255     # Set to 0 for darkest and 255 for brightest
LED_INVERT     = False   # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL    = 0       # set to '1' for GPIOs 13, 19, 41, 45 or 53
LED_STRIP      = ws.WS2811_STRIP_GRB   # Strip type and colour ordering

#This section is used to define what is going to be delated or changed, feel free to modify it.
cadena1 = "defaultdict(<type 'dict'>, {5: {'SEQ': 1, 'BODY[1]': '"
cadena2 = '<span class="after">Name</span>'
cadena3 = "</td>"
cadena4 = "="
cadena5 = '<strong><a href"Kommentar'
cadena6 = "</a>"
cadena7 = "</strong>"
cadena8 = '<td style"padding:0.9em 0.4em; text-align:right;">'
cadena9 = '<td style"padding:0.9em 0.4em; text-align:right;">'
cadena10 = '<td style"padding:0.9em 0.4em; text-align:center;">'
cadena11 = '<td style"padding:0.9em 0.4em; text-align:right;">'
cadena12 = "</tr>"
cadena13 = '\\t'
cadena14 = '\\r'
cadena15 = '\\n'
cadena16 = "'}})"
cadena17 = '<span style"color:; font-weight:bold;'
cadena18 = '</span>'
cadena19 = '<tr style"background-color:'
cadena20 = 'EBECEE;">'
cadena21 = '<br />'
cadena22 = '">' #'html">'
cadena23 = '$ '
cadena24 = '<br  />'
cadena25 = '<span  style"color:; font-weight:bold;">'
cadena26 = '. '
cadena27 = 'DDE2E6;">'
cadena28 = '<span style"color:; font-weight:bold;">'
cadena29 = 'e :'
cadena30 = "defaultdict(<type 'dict'>, {5: {'SEQ': 1, 'BODY[1]': '"

# This function deletes or changes the parts of the email that we dont want. Uses the strings above. 
def decode_email(msg_str):
    body = quopri.decodestring(msg_str) #decodes
    #body = body[0:] #start from character number...
    #body = body[:230] #end in character number...
    body = string.replace(body,cadena1, ' ')
    body = string.replace(body,cadena2, ' ')
    body = string.replace(body,cadena3, ' ')
    body = string.replace(body,cadena4, '')
    body = string.replace(body,cadena5, ' ')
    body = string.replace(body,cadena6, ' ')
    body = string.replace(body,cadena7, ' ')
    body = string.replace(body,cadena8, '')
    body = string.replace(body,cadena9, '')
    body = string.replace(body,cadena10, ' ')
    body = string.replace(body,cadena11, '')
    body = string.replace(body,cadena12, '')
    body = string.replace(body,cadena13, '')
    body = string.replace(body,cadena14, '')
    body = string.replace(body,cadena15, ' ')
    body = string.replace(body,cadena16, '')
    body = string.replace(body,cadena17, ' ')
    body = string.replace(body,cadena18, ' ')
    body = string.replace(body,cadena19, '')
    body = string.replace(body,cadena20, ' ')
    body = string.replace(body,cadena21, ' ')
    body = string.replace(body,cadena22, ' ')
    body = string.replace(body,cadena23, '$')
    body = string.replace(body,cadena24, ' ')
    body = string.replace(body,cadena25, ' ')
    body = re.sub('\s{2,}', ' ', body) #deletes double or more white spaces and left it as one space.
    body = string.replace(body,cadena26, '.')
    body = string.replace(body,cadena27, '')
    body = string.replace(body,cadena28, '')
    body = string.replace(body,cadena29, 'e:')
    body = string.replace(body,cadena30, ' ')
    body = re.sub('\s{2,}', ' ', body) #deletes double or more white spaces and left it as one space.
    body = unicode(str(body), 'utf-8') #character decodification
    msg = body
    decoded_message = msg
    return decoded_message

#This function generates and prints our ticket based in the received info. (not used in the instructables example, but feel free to modify it) 
def ticket_summary (body2):
    #pos = body2.find('PEDIDO ') #search for a keyword
    #ordernum = body2[pos + 8:pos +17] #and extracts the info next to it. Of course we know what we are searching for ;)
    pos1 = body2.find('Name') 
    pos2 = body2.find('Telefon')
    pos3 = body2.find('Email')
    pos4 = body2.find('Personen')
    pos5 = body2.find('Datum')
    pos6 = body2.find('Uhrzeit')
    pos7 = body2.find('Tisch')
    pos8 = body2.find('Kommentar :')
    persons = body2[pos4:pos5]
    date = body2[pos5:pos6]
    time = body2[pos6:pos7]
    email = body2[pos3:pos4]
    tel = body2[pos2:pos3]
    name = body2[pos1:pos2]
    table = body2[pos7:pos8]
    #comment = body2[pos8 +5]
    printer.justify('L') #now the ticket is being printed
   # printer.println("--------------------------------")
   # printer.feed(2)
    #printer.printImage(Image.open('dafr webpage mono.bmp'),True)
    printer.println("Neue Online Reservierung")
    printer.println("================================")
    printer.feed(1)
    printer.println(name)
    printer.println(time)
    printer.println(persons)
    printer.println(table)
    printer.println(date)
    printer.println(tel)
    printer.println(email)
   # printer.println(comment)
    printer.println("================================")
    printer.justify('C')
    #printer.println("GRACIAS POR TU COMPRA!")
    #printer.println("www.dafrelectronics.com")
    printer.feed(1)
   # printer.println("------ REV:2A07012015DAFR ------")
   # printer.feed(3)
    return



# Called when button is briefly tapped.  Invokes time/temperature script.
def tap():
  loop() #checks our inbox
  return

# Called when button is held down.  Prints image, invokes shutdown process.
def hold():
  subprocess.call("sync")
  subprocess.call(["shutdown", "-h", "now"]) #shutdowns the raspberry pi
  strip.setPixelColorRGB(0,0,0,0) #turn off the neopixel
  strip.show()
  printer.sleep()
  return

# Create NeoPixel object with appropriate configuration.
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
# Intialize the library (must be called once before other functions).
strip.begin()

#Create thermal printer object and load default configuration.
printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout=5)

#Program start here:
strip.setPixelColorRGB(0,0,255,0) #booting script state, green color is showed in the neopixel.
strip.show()

 
DEBUG = True  #Change it to False when you are done debugging

# Here you can enter your email login details. 
HOSTNAME = 'imap.gmail.com'
USERNAME = 'user@gmail.com'
PASSWORD = '000000'
MAILBOX = 'Secret messages'
 
NEWMAIL_OFFSET = 0   # only executes printing after the emails reach the minimun for processing.
MAIL_CHECK_FREQ = 60 # check mail every 60 seconds, you can change it.
 
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

buttonPin    = 23

GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

prevButtonState = GPIO.input(buttonPin)
prevTime        = time.time()
tapEnable       = False
holdEnable      = False
tapTime      = 0.01  # Debounce time for button taps
nextInterval = 0.0   # Time of next recurring operation
holdTime     = 5     # Duration for button hold (shutdown)

counter = 0

time.sleep(10)
 
def loop():
  try:  
    server = IMAPClient(HOSTNAME, use_uid=True, ssl=True)
    server.login(USERNAME, PASSWORD)
    
    select_info = server.select_folder(MAILBOX) 

    if DEBUG:
        print('Logging in as ' + USERNAME)
        print('%d messages in "Secret messages"' % select_info['EXISTS'])
 
    folder_status = server.folder_status(MAILBOX, 'UNSEEN')
    newmails = int(folder_status['UNSEEN'])
 
    if DEBUG:
        print "You have", newmails, "new recent emails!"


    messages = server.search(['UNSEEN']) #NOT DELETED to see all email available 

    if DEBUG:
        print("There are %d messages that aren't read" % len(messages))  
        print("Messages:")

    response = server.fetch(messages, ['FLAGS', 'RFC822.SIZE'])
    mail_array = []
    
    for msgid, data in response.iteritems():
        if DEBUG:
            print('   ID %d: %d bytes, flags=%s' % (msgid, data[b'RFC822.SIZE'], data[b'FLAGS']))    
        mail_array.append(msgid)
    
    if DEBUG:
       for elements  in mail_array:
           print(elements)
       

    
    if newmails > NEWMAIL_OFFSET:
        strip.setPixelColorRGB(0,0,0,255) #turn blue our neopixel if we have something to print
        strip.show()


        printer.wake()    
        time.sleep(5)
        printer.feed(1)

        for elements in mail_array:
            if printer.hasPaper() == True: #verify is printer has paper before printing.
               body = server.fetch(elements,['BODY.PEEK[1]']) #IMPORTANT you might have problems with these, try using "1", "1.1", "1.2" or "2". 
               if DEBUG:
                  print(body) #prints in console original text.
                  print(' ')
               body2 = decode_email(str(body)) #process the received text.
               if DEBUG:
                  print (body2) #prints in console processed text.
               ticket_summary(body2) #call the ticket printing routine
               printer.println(body2) #prints in paper the original text of the email. Change to "body2" for printing the processed version.
               if printer.hasPaper() == True: #verify is printer has paper after printing.
                  server.add_flags(elements, '\\Seen')  #mark as read if printed sucesfully.
               else:
                  strip.setPixelColorRGB(0,255,255,0) #show yellow neopixel if there is no paper in the printer.
                  strip.show()
                  if DEBUG:
                     print 'There is no paper in the printer.'
               if DEBUG:
                  print(' ')
                  time.sleep(12)
            else:
              strip.setPixelColorRGB(0,255,255,0) #show yellow neopixel if there is no paper in the printer.
              strip.show()
              if DEBUG:
                 print 'There is no paper in the printer.'
        printer.sleep() 
        
    else:
        strip.setPixelColorRGB(0,255,0,0) #show red neopixel if there are no emails for printing.
        strip.show()
        
  except:
    strip.setPixelColorRGB(0,255,0,255) #show purple neopixel if an error occurs reading the email.
    strip.show()
    if DEBUG:
        print 'Cant check email or an error has ocurred. Verify your internet conection or this script parameters'
 
    
 
if __name__ == '__main__':
    try:
        if DEBUG:
            print 'Press ctrl + c to quit'
        printer.wake()
        printer.sleep()
        strip.setPixelColorRGB(0,255,255,255) #show white neopixel while starting up. 
        strip.show()
        time.sleep(5)
        loop()
                    
        while True:
           time.sleep(1)
           # Poll current button state and time
           buttonState = GPIO.input(buttonPin)
           t           = time.time()
           # Has button state changed?
           if buttonState != prevButtonState:
              prevButtonState = buttonState   # Yes, save new state/time
              prevTime        = t
           else:                             # Button state unchanged
            if (t - prevTime) >= holdTime:  # Button held more than 'holdTime'?
              # Yes it has.  Is the hold action as-yet untriggered?
               if holdEnable == True:        # Yep!
                  hold()                      # Perform hold action (usu. shutdown)
                  holdEnable = False          # 1 shot...don't repeat hold action
                  tapEnable  = False          # Don't do tap action on release
            elif (t - prevTime) >= tapTime: # Not holdTime.  tapTime elapsed?
             # Yes.  Debounced press or release...
               if buttonState == True:       # Button released?
                 if tapEnable == True:       # Ignore if prior hold()
                    tap()                     # Tap triggered (button released)
                    tapEnable  = False        # Disable tap and hold
                    holdEnable = False
               else:                         # Button pressed
                 tapEnable  = True           # Enable tap and hold actions
                 holdEnable = True
           if counter >= MAIL_CHECK_FREQ:   
              loop()
              counter = 0
           else:
              counter = counter + 1
               
    finally:
        GPIO.cleanup() #reset the gpio pins functions.
        strip.setPixelColorRGB(0,0,0,0) #turn off neopixel at exit of this script. (shutting down or ctrl + c)
        strip.show()
        printer.sleep()
Zuletzt geändert von xdowner am Montag 18. Dezember 2017, 16:49, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Damit kann man nichts anfangen. Bitte in die Code-Tags setzen. Dazu den Quellcode markieren, und "Code auswaehlen" auswaehlen. Dann Python auswaehlen.

So ist alles linksbuendig zusammengemanscht, und verliert damit seine Bedeutung.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

So wie das aussieht prozessierst du den body komplett, da wird doch nichts weggeschnitten. Was also passt dann nicht?
xdowner
User
Beiträge: 5
Registriert: Sonntag 17. Dezember 2017, 19:06

__deets__ hat geschrieben:So wie das aussieht prozessierst du den body komplett, da wird doch nichts weggeschnitten. Was also passt dann nicht?
Im geposteten code hatte ich testweise den body auskommentiert (start und endpunkt) leider half das nicht. So sieht es normalerweise aus.

Code: Alles auswählen

def decode_email(msg_str):
    body = quopri.decodestring(msg_str) #decodes
    body = body[0:] #start from character number...
    body = body[:230] #end in character number...
Mein Problem ist, dass er von Zeichen 0-230 prozessiert. Wenn ich den Wert von 0-300 Zeichen ändere und meine Email z.B. 230 hat, dann bekomme ich eine Fehlermeldung. Es sieht so aus als ob er dann im loop immer wieder von vorne anfängt. Einen Teil ausdruckt bis er zum Fehler kommt und dann wieder von vorne anfängt.

Code: Alles auswählen

pi@ReservierungsDrucker:~/IoTprinter $ sudo python mailverifierMarc.py
Press ctrl + c to quit
Logging in as email@gmail.com
1 messages in "Secret messages"
You have 1 new recent emails!
There are 1 messages that aren't read
Messages:
   ID 5: 5732 bytes, flags=()
5
defaultdict(<type 'dict'>, {5: {'SEQ': 1, 'BODY[1]': 'Name : Schmidt\r\nTelefon : 0305553821\r\nEmail : heiko@charite.de\r\nPersonen : 8\r\nDatum : Don 07.12.2017\r\nUhrzeit : 12:30\r\nTisch : egal\r\nKommentar : bitte um R=C3=BCckmeldung,\r\nvielen Dank\r\n'}})

 Name: Schmidt Telefon : 030555821 Email : heikox@charite.de Personen : 8 Datum : Don 07.12.2017 Uhrzeit : 12:30 Tisch : egal Kommentar : bitte um Rückmeldung, vielen Dank
Cant check email or an error has ocurred. Verify your internet conection or this script parameters
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich glaube nicht, das du einen Fehler bekommst, wenn du das auf 300 setzt. Das ignoriert Python naemlich.

Code: Alles auswählen

>>> s = "A" * 230
>>> s[:300]
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
Ich erzeuge einen String mit 230 Zeichen, und versuch den zu slicen bis 300 - und das Ergebnis ist halt der gesamte String. Da kommt kein Fehler.

Was aber ein Problem ist, ist dein try/except in loop. Das schluckt naemlich *ALLE* Fehler einfach mal weg. Womit du (und wir) voellig im dunkeln tappen, was da wirklich schief geht. Das wuerde ich rausschmeissen, um dir mal anzuschauen, was der wirkliche Fehler ist. Oder mindestens logging einbauen, mit dem du die tatsaechliche Exception ausgibst.
xdowner
User
Beiträge: 5
Registriert: Sonntag 17. Dezember 2017, 19:06

Das ist seltsam, sobald ich den Wert über die vorhandene Zeichenanzahl setze bekomme ich den Fehler bzw. erzeugt den loop. Alle Werte die innerhalb der real Exestierenden Zeichen sind lassen das script tadellos funktionieren.
Kannst du mir sagen was ich für den Log einbauen muss? :|
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schmeiß das try/except erstmal weg. Dann poste die echte Fehlermeldung, in Gänze.

Bzw einfacher ist

Code: Alles auswählen

try:
    ...
except:
    raise
    ...
Das schmeißt den Fehler dann wieder.
xdowner
User
Beiträge: 5
Registriert: Sonntag 17. Dezember 2017, 19:06

Vielen Dank ich konnte den Fehler finden. Es lag an den Umlauten mit den er nicht klar kam!

Code: Alles auswählen

 #body = unicode(str(body), 'utf-8') #character decodification
Ich habe den utf-8 string auskommentiert und nun druckt er den ganzen Text. Er druckt zwar seltsame Zeichen statt einem Umlaut damit kann ich aber Notfalls leben.

Zudem habe ich ihm gesagt das es den ganzen body decodieren soll.

Code: Alles auswählen

    body = quopri.decodestring(msg_str) #decodes
    length = len(body) -1
    body = body[0:] #start from character number...
    body = body[:length] #end in character number...
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das was du da machst für „den gesamten Body“ ist Unfug.

Body enthält schon alles. Zweimal daran rumzuschnippeln mit der Absicht, alles zu behalten ist überflüssig. Und deine erklärte Absicht erreichst du auch nicht, da du immer noch den letzten Buchstaben abschneidest.

Lass das einfach weg.
Antworten