Ankündigung

Einklappen
Keine Ankündigung bisher.

Mail-Plugin - Mail mit Anhängen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Mail-Plugin - Mail mit Anhängen

    Im konkreten Anwendungfall soll eine Mail mit dem Bild von der IP-Webcam verschickt werden wenn niemand zu Hause ist. Die Mail selber zu versenden ist ja dank dem Plugin nicht das Problem. Nur soll die Mail noch mit besagtem Anhang versehen werden.
    Der Pfad zum Bild ist z.B. http://192.168.1.100:8888/shot.jpg

    Hat jemand ne Idee (oder es bereits umgesetzt) wie man das realisieren kann?

    Danke

    #2
    19.1.13. email: Examples ? Python v3.3.2 documentation ?

    Täte mich aber aus dem gleichen Grund auch interessieren. Eine erweiterte Funktion die von einer URL als auch einem Verzeichnis ein Bild anhängen kann würde für 95% der Fälle wohl schon reichen. Wer dann mehr Bilder braucht kann das ja mit der oben geposteten Anleitung direkt in einer Logik abfrühstücken.

    Kommentar


      #3
      Gibt es dafür ein Beispiel, wie ich ein Bild, das auf meinem smarthome.py Server liegt einfach ins Mail integrieren kann?
      Ohne, dass ich das mail-plugin ändern muss?

      thx, Bernhard

      Kommentar


        #4
        Ich hab mich heute Abend mal dran gesetzt und das Mail-Plugin aufgebohrt.

        Funktioniert soweit:

        sh.mail(empfaenger, betreff, nachricht) -> ohne Anhang
        sh.mail(empfaenger, betreff, nachricht, '/var/log/syslog') -> ein Anhang als string
        sh.mail(empfaenger, betreff, nachricht, ['/var/log/syslog','/var/log/smarthome.log']) -> mehrere Anhänge als Liste

        Vielleicht kann es noch jemand gebrauchen, ich fürchte aber da Marcus von Release spricht hat er da schon was vorbereitet. Ich habs (noch) nicht ins git geschoben da meine Codequalität sicherlich nicht so toll ist .
        Hatte aber gute Quellen: https://docs.python.org/3/library/email-examples.html

        Hier für die experimentierfreudigen unter Euch die
        /plugins/mail/__init__py:
        Code:
        #!/usr/bin/env python3
        # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
        #########################################################################
        #  Copyright 2012-2013 Marcus Popp                         marcus@popp.mx
        #########################################################################
        #  This file is part of SmartHome.py.    http://mknx.github.io/smarthome/
        #
        #  SmartHome.py is free software: you can redistribute it and/or modify
        #  it under the terms of the GNU General Public License as published by
        #  the Free Software Foundation, either version 3 of the License, or
        #  (at your option) any later version.
        #
        #  SmartHome.py is distributed in the hope that it will be useful,
        #  but WITHOUT ANY WARRANTY; without even the implied warranty of
        #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        #  GNU General Public License for more details.
        #
        #  You should have received a copy of the GNU General Public License
        #  along with SmartHome.py. If not, see <http://www.gnu.org/licenses/>.
        #########################################################################
        
        import logging
        import imaplib
        import smtplib
        import email
        import os
        import mimetypes
        from email.mime.text import MIMEText
        from email.header import Header
        from email.mime.multipart import MIMEMultipart
        from email.mime.base import MIMEBase
        from email.mime.audio import MIMEAudio
        from email.mime.image import MIMEImage
        from email.message import Message
        from email import encoders
        
        logger = logging.getLogger('')
        
        
        class IMAP():
        
            def __init__(self, smarthome, host, username, password, cycle=300, port=None, ssl=False):
                self._sh = smarthome
                self._ssl = smarthome.string2bool(ssl)
                self._host = host
                self._port = port
                self._username = username
                self._password = password
                self._mail_sub = {}
                self._mail_to = {}
                self._mail = False
                self._sh.scheduler.add('IMAP', self._cycle, cycle=int(cycle))
        
            def _connect(self):
                if self._ssl:
                    if self._port is not None:
                        imap = imaplib.IMAP4_SSL(self._host, self._port)
                    else:
                        imap = imaplib.IMAP4_SSL(self._host)
                else:
                    if self._port is not None:
                        imap = imaplib.IMAP4(self._host, self._port)
                    else:
                        imap = imaplib.IMAP4(self._host)
                imap.login(self._username, self._password)
                return imap
        
            def _cycle(self):
                try:
                    imap = self._connect()
                except Exception as e:
                    logger.warning("Could not connect to {0}: {1}".format(self._host, e))
                    return
                rsp, data = imap.select()
                if rsp != 'OK':
                    logger.warning("IMAP: Could not select mailbox")
                    imap.close()
                    imap.logout()
                    return
                rsp, data = imap.uid('search', None, "ALL")
                if rsp != 'OK':
                    logger.warning("IMAP: Could not search mailbox")
                    imap.close()
                    imap.logout()
                    return
                uids = data[0].split()
                for uid in uids:
                    if not self.alive:
                        break
                    try:
                        rsp, data = imap.uid('fetch', uid, '(RFC822)')
                        if rsp != 'OK':
                            logger.warning("IMAP: Could not fetch mail")
                            continue
                        mail = email.message_from_bytes(data[0][1])
                        to = email.utils.parseaddr(mail['To'])[1]
                        fo = email.utils.parseaddr(mail['From'])[1]
                        subject, encoding = email.header.decode_header(mail['Subject'])[0]
                        if encoding is not None:
                            subject = subject.decode(encoding)
                    except Exception as e:
                        logger.exception("IMAP: problem parsing message {}: {}".format(uid, e))
                        continue
                    if subject in self._mail_sub:
                        logic = self._mail_sub[subject]
                    elif to in self._mail_to:
                        logic = self._mail_to[to]
                    elif self._mail:
                        logic = self._mail
                    else:
                        logic = False
                    if logic:
                        logic.trigger('IMAP', fo, mail, dest=to)
                        rsp, data = imap.uid('copy', uid, 'Trash')
                        if rsp == 'OK':
                            typ, data = imap.uid('store', uid, '+FLAGS', '(\Deleted)')
                            logger.debug("Moving mail to trash. {0} => {1}: {2}".format(fo, to, subject))
                        else:
                            logger.warning("Could not move mail to trash. {0} => {1}: {2}".format(fo, to, subject))
                    else:
                        logger.info("Ignoring mail. {0} => {1}: {2}".format(fo, to, subject))
                imap.close()
                imap.logout()
        
            def run(self):
                self.alive = True
        
            def stop(self):
                self.alive = False
        
            def parse_item(self, item):
                pass
        
            def parse_logic(self, logic):
                if 'mail_subject' in logic.conf:
                    self._mail_sub[logic.conf['mail_subject']] = logic
                if 'mail_to' in logic.conf:
                    self._mail_to[logic.conf['mail_to']] = logic
                if 'mail' in logic.conf:
                    self._mail = logic
        
            def update_item(self, item, caller=None, source=None, dest=None):
                pass
        
        
        class SMTP():
        
            def __init__(self, smarthome, host, mail_from, username=False, password=False, port=25, ssl=False):
                self._sh = smarthome
                self._ssl = smarthome.string2bool(ssl)
                self._host = host
                self._port = int(port)
                self._from = mail_from
                self._username = username
                self._password = password
        
            def __call__(self, to, sub, content, files=False):
                try:
                    smtp = self._connect()
                except Exception as e:
                    logger.warning("Could not connect to {0}: {1}".format(self._host, e))
                    return
                try:
                    text = (MIMEText(content, 'plain', 'utf-8'))
                    msg = MIMEMultipart()
                    msg['Subject'] = Header(sub, 'utf-8')
                    msg['From'] = self._from
                    msg['Date'] = email.utils.formatdate()
                    msg['To'] = to
                    msg['Message-ID'] = email.utils.make_msgid('SmartHome.py')
                    to = [x.strip() for x in to.split(',')]
                    msg.attach(text)
                    filelist = []
                    if files:
                        if type(files) is str:
                            filelist.append(files)
                        else:
                            filelist.extend(files)
                            
                        for filename in filelist:
                            ctype, encoding = mimetypes.guess_type(filename)
                            if ctype is None or encoding is not None:
                                ctype = 'application/octet-stream'
                            maintype, subtype = ctype.split('/', 1)
                            if maintype == 'text':
                                with open(filename) as fp:
                                    file = MIMEText(fp.read(), _subtype=subtype)
                            elif maintype == 'image':
                                with open(filename, 'rb') as fp:
                                    file = MIMEImage(fp.read(), _subtype=subtype)
                            elif maintype == 'audio':
                                with open(filename, 'rb') as fp:
                                    file = MIMEAudio(fp.read(), _subtype=subtype)
                            else:
                                with open(filename, 'rb') as fp:
                                    file = MIMEBase(maintype, subtype)
                                    file.set_payload(fp.read())
                                encoders.encode_base64(file)
        
                            base_filename = os.path.basename(filename)
        
                            file.add_header('Content-Disposition', 'attachment', filename=base_filename)
                            msg.attach(file)
                            
        
                    smtp.sendmail(self._from, to, msg.as_string())
                    
                except Exception as e:
                    logger.warning("Could not send message {} to {}: {}".format(sub, to, e))
                finally:
                    try:
                        smtp.quit()
                        del(smtp)
                    except:
                        pass
        
            def _connect(self):
                smtp = smtplib.SMTP(self._host, self._port)
                if self._ssl:
                    smtp.starttls()
                if self._username:
                    smtp.login(self._username, self._password)
                return smtp
        
            def run(self):
                self.alive = True
        
            def stop(self):
                self.alive = False
        
            def parse_item(self, item):
                pass
        
            def parse_logic(self, logic):
                pass
        
            def update_item(self, item, caller=None, source=None, dest=None):
                pass
        Grüße Mirko
        Zuletzt geändert von JuMi2006; 09.03.2015, 15:06.
        Umgezogen? Ja! ... Fertig? Nein!
        Baustelle 2.0 !

        Kommentar


          #5
          Bin gerade am Testen der Anhang-Sache.. funzt soweit mit nem Logfile 1A - vielen Dank!

          Kommentar


            #6
            Hi zusammen!
            Ab und an bekomme ich folgende Fehlermeldung vom Mail Plugin.. ich bin mir nicht sicher, ob es vom "Anhang-Fix" kommt oder auch generell da wäre. Werde ich natürlich in nächster Zeit mal testen, aber vielleicht kennt jemand die Meldung oder kann sich was drunter vorstellen ?
            Code:
            2016-01-10 11:12:44,672 DEBUG    Scheduler    IMAP next time: 2016-01-10 11:17:44+01:00 -- scheduler.py:_next_time:303
            2016-01-10 11:12:44,796 ERROR    IMAP         IMAP: problem parsing message b'833': 'NoneType' object is not subscriptable -- __init__.py:_cycle:95
            Traceback (most recent call last):
              File "/usr/smarthome/plugins/mail/__init__.py", line 88, in _cycle
                mail = email.message_from_bytes(data[0][1])
            TypeError: 'NoneType' object is not subscriptable
            Kommt vielleicht 1 Mal am Tag, wenn überhaupt. Sonst funzt alles top.

            Kommentar


              #7
              Hallo zusammen!

              Ich versuche gerade, mit dem mail-plugin html-formatierte emails zu versenden. Leider klappt das nicht so richtig. Ein workaround wäre, das per system-call zu machen... Wie macht ihr das denn bzw. habt ihr Vorschläge wie ihr das machen würdet?

              Gruß,
              //giase

              Kommentar


                #8
                Hallo, möchte das Thema noch einmal aufgreifen.
                So wie ich die __init__.py lese, kann man auch E-Mails im html-Format verschicken.
                Ich würde gerne eine Bilddatei (jpg) in die E-Mail einbinden. Leider werde ich aus dem Code nicht schlau. Und in der Doku steht dazu nichts.
                Vielleicht kann mir jemand auf die Sprünge helfen, wie man ein Bild direkt einbindet.

                Vielen Dank.
                Grüße
                Thomas

                Kommentar


                  #9
                  Wenn ich den Code und mein MIME-Wissen richtig interpretiere, kannst du das Bild per   <img src="cid:imageNR">  einbinden.
                  NR ist dabei der 0-basierte Index des angehängten Bildes (also cid:image0 wäre das erste Bild).

                  Kommentar


                    #10
                    Sorry, aber ich steige immer noch nicht durch. Folgendes habe ich schonmal:
                    Code:
                    sh.mail.extended('xxx@xyz.com', 'Sie haben einen Besucher verpasst!', Text, 'SmartHomeNG')
                    Soweit funktioniert das. E-Mail wird verschickt, Inhalt passt. Absender passt.

                    Das Bild, das ich einbinden möchte, heisst /usr/local/smarthome/Bilder/test.jpg
                    Wenn ich jetzt diesen Dateinamen als 5. Stelle im Code angebe, kommt die Fehlermeldung: [Errno 21] Ist ein Verzeichnis: '/'
                    Habe schon alles mögliche probiert. Aber werde nicht schlau aus dem Code.

                    Kommentar


                      #11
                      Für die Bilder und Attachments wird gemäss der Signatur bzw. Standardwerte wahrscheinlich eine Liste erwartet.
                      Die Fehlermeldung würde auch passen, weil wahrscheinlich so über den String statt die Liste iteriert wird, der erste "Eintrag" ist dann ein "/".
                      Code:
                      def extended(self, to, sub, msg, sender_name: str, img_list: list=[], attachments: list=[]):

                      Kommentar


                        #12
                        Ok. Soweit klar.
                        Und wie kann ich jetzt dem Plugin mitteilen, dass die Liste genau ein Element enthält, nämlich die Bilddatei mit dem angegebenen Pfad?

                        Kommentar


                          #13
                          Indem du eine Liste mit einem Element übergibst.
                          In deinem Fall also
                          Code:
                          sh.mail.extended('xxx@xyz.com', 'Sie haben einen Besucher verpasst!', Text, 'SmartHomeNG', ['/usr/local/smarthome/Bilder/test.jpg'])

                          Kommentar


                            #14
                            Super. Jetzt funktionierts. Hochkommata falsch gesetzt

                            Vielen Dank.

                            Kommentar


                              #15
                              Ist mail.extended() eigentlich irgendwo dokumentiert? Ich habe nichts dazu gefunden.

                              Kommentar

                              Lädt...
                              X