Seite 1 von 1

Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 12:56
von Nobuddy
Hallo zusammen,

für meinen EMail-Versand, habe ich hier http://codecocktail.wordpress.com/2008/ ... versenden/ ein schönes Programm gefunden, das ich für meine Bedürfnisse angepasst habe.

Hier mal das Programm:

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Sende alle Dateien per Mail
#Example usage: python sendMail.py file1.txt, file2.txt ...

import sys, smtplib, os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email import Encoders

class SendMail(object):
    mailadress = 'email@mail.de'
    smtpserver = 'mail.de'
    username = 'usernamen'
    password = 'password'
    empfaenger = 'empfaenger@gmx.de'

    def send(self, files):
        # Gather information, prepare mail
        to = self.empfaenger
        From = self.mailadress
        #Subject contains preview of filenames
        if len(files) <= 3: subjAdd = ','.join(files)
        if len(files) > 3: subjAdd = ','.join(files[:3]) + '...'
        subject = 'Bestellung: ' + subjAdd
        msg = self.prepareMail(From, to, subject, files)

        #Connect to server and send mail
        server = smtplib.SMTP(self.smtpserver)
        server.ehlo() #Has something to do with sending information
        server.starttls() # Use encrypted SSL mode
        server.ehlo() # To make starttls work
        server.login(self.username, self.password)
        failed = server.sendmail(From, to, msg.as_string())
        server.quit()

    def prepareMail(self, From, to, subject, attachments):
        msg = MIMEMultipart()
        msg['From'] = From
        msg['To'] = to
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject

        # The Body message is empty
        msg.attach( MIMEText("") )

        for file in attachments:
            #We could check for mimetypes here, but I'm too lazy
            part = MIMEBase('application', "octet-stream")
            part.set_payload( open(file,"rb").read() )
            Encoders.encode_base64(part)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
            msg.attach(part)
        #Delete created Tar
        return msg

if __name__ == '__main__':
    mail = SendMail()
    # Send all files included in command line arguments
    mail.send(sys.argv[1:])
Wenn ich dieses Programm aus dem Terminal mit

Code: Alles auswählen

python __modul_email__.py '/home/user/a/999mail.txt'
aufrufe, so wird die Mail mit Anhang verschickt. Dies funktioniert auch soweit problemlos.

Nun möchte ich aber nicht vom Terminal aus EMails mit Anhang versenden, sondern über ein eigens erstelltes Python-Programm. Leider ist es mir bis jetzt nicht gelungen, dies umzusetzen. :K

Ich würde mich über Eure Hilfe hier sehr freuen!

Grüße Nobuddy

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 13:05
von deets
Wie bist du denn auf diesen absurden Modulnamen gekommen?

Prinzipiell ist es ganz simpel:

Code: Alles auswählen

from besserer_modulname import SendMail


def meine_funktion():
      m = SendMail()
      m.send(filename)

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 13:57
von Nobuddy
Hallo deets,

mit

Code: Alles auswählen

files = '/home/whtb/a/999officeplanet.txt'

from __modul_email__ import SendMail

def meine_funktion():
      m = SendMail()
      m.send(files)
tut sich nichts und mit

Code: Alles auswählen

files = '/home/whtb/a/999officeplanet.txt'

from __modul_email__ import SendMail

def meine_funktion():
      m = SendMail()
      m.send(files)

meine_funktion()
erhalte ich die Fehlermeldung

Code: Alles auswählen

Traceback (most recent call last):
  File "a.py", line 32, in <module>
    meine_funktion()
  File "a.py", line 30, in meine_funktion
    m.send(files)
  File "/media/daten/Scripte/officeplanet/lieferantenbestellung/__modul_email__.py", line 29, in send
    msg = self.prepareMail(From, to, subject, files)
  File "/media/daten/Scripte/officeplanet/lieferantenbestellung/__modul_email__.py", line 53, in prepareMail
    part.set_payload( open(file,"rb").read() )
IOError: [Errno 21] Is a directory: '/'
Während der Befehl im Terminal

Code: Alles auswählen

python __modul_email__.py '/home/user/a/999mail.txt'
funktioniert.

Was mache ich da falsch?

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 14:16
von cofi
Nobuddy hat geschrieben:Was mache ich da falsch?
Schau mal ganz genau hin, was die `send` Methode erwartet und womit du sie aufrufst. Alternativ kannst du dir auch anschauen, was `attachements` in `prepareMail` sein sollte.

Code: Alles auswählen

In [1]: list('kleiner tipp')
Out[1]: ['k', 'l', 'e', 'i', 'n', 'e', 'r', ' ', 't', 'i', 'p', 'p']

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 14:49
von Nobuddy
An Deinem Beispielcode, sehe ich was Du mir mitteilen willst.
Leider ist mir nicht klar, wie ich bei `attachements` in `prepareMail` ansetzen soll?

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 15:49
von cofi

Code: Alles auswählen

def prepareMail(self, From, to, subject, attachments):
    ...
    for file in attachments:
Da du hier _einen_ Pfad uebergibst, ist `file` das erste Mal eben das erste Zeichen des Strings: '/'.

Mit anderen Worten: Nutze eine Liste von Strings, wie der Original Code das auch tut.

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 16:44
von Nobuddy
Ich habe dies so geändert:

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Sende alle Dateien per Mail
#Example usage: python sendMail.py file1.txt, file2.txt ...

import sys, smtplib, os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email import Encoders

class SendMail(object):
    mailadress = 'email@mail.de'
    smtpserver = 'mail.de'
    username = 'usernamen'
    password = 'password'
    empfaenger = 'empfaenger@gmx.de'

    def send(self, files):
        # Gather information, prepare mail
        to = self.empfaenger
        From = self.mailadress
        attachment = files
        # Subject contains preview of filenames
        # if len(files) <= 3: subjAdd = ','.join(files)
        # if len(files) > 3: subjAdd = ','.join(files[:3]) + '...'
        # subject = 'Bestellung: ' + subjAdd
        subject = 'Bestellung'
        msg = self.prepareMail(From, to, subject, attachment)

        #Connect to server and send mail
        server = smtplib.SMTP(self.smtpserver)
        server.ehlo() #Has something to do with sending information
        server.starttls() # Use encrypted SSL mode
        server.ehlo() # To make starttls work
        server.login(self.username, self.password)
        failed = server.sendmail(From, to, msg.as_string())
        server.quit()

    def prepareMail(self, From, to, subject, attachment):
        msg = MIMEMultipart()
        msg['From'] = From
        msg['To'] = to
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject

        # The Body message is empty
        msg.attach( MIMEText("") )
        print(attachment)

        #We could check for mimetypes here, but I'm too lazy
        part = MIMEBase('application', "octet-stream")
        part.set_payload( open(attachment,"rb").read() )
        Encoders.encode_base64(part)
        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(attachment))
        msg.attach(part)
        #Delete created Tar
        return msg

if __name__ == '__main__':
    mail = SendMail()
    # Send all files included in command line arguments
    mail.send(sys.argv[1:])
und funktioniert mit dem externen Aufruf

Code: Alles auswählen

files = '/home/user/a/999officeplanet.txt'

from __modul_email__ import SendMail

def meine_funktion():
      m = SendMail()
      m.send(files)

meine_funktion()
Allerdings funktionieren mehrere Anhänge pro Mail nicht.

Re: Programm aufrufen

Verfasst: Mittwoch 23. Mai 2012, 18:37
von cofi
Nobuddy hat geschrieben:Allerdings funktionieren mehrere Anhänge pro Mail nicht.
Noch die eigenstaendige Verwendung des Programms.

Die naheliegende Veraenderung waere

Code: Alles auswählen

files = '/home/user/a/999officeplanet.txt'
zu

Code: Alles auswählen

files = ['/home/user/a/999officeplanet.txt']
gewesen .. dann wuerde auch der Plural Sinn machen.

Re: Programm aufrufen

Verfasst: Donnerstag 24. Mai 2012, 08:46
von Nobuddy
cofi, Danke für Deine Tipp, jetzt funktioniert dies auch mit mehreren Anhängen.

Hier nochmal das aktuelle Konstrukt:

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-


import sys, smtplib, os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email import Encoders


# EMail-Versand mit Anhang
class SendMail(object):
    def send(self, mailadress, smtpserver, username, password, files, empfaenger, subject):
        # EMail vorbereiten, Informationen sammeln
        to = empfaenger
        From = mailadress
        attachment = files
        msg = self.prepareMail(From, to, subject, attachment)

        # Verbinden zu einem Server und E-Mail senden
        server = smtplib.SMTP(smtpserver)
        server.ehlo() # Hat etwas mit Senden von Informationen zu tun
        server.starttls() # SSL-Modus verwenden
        server.ehlo() # TLS starten
        server.login(username, password)
        failed = server.sendmail(From, to, msg.as_string())
        server.quit()

    def prepareMail(self, From, to, subject, attachment):
        msg = MIMEMultipart()
        msg['From'] = From
        msg['To'] = to
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject

        # Der Body-Nachricht ist leer
        msg.attach( MIMEText("") )

        for file in attachment:
            # Wir könnten hier für die MIME-Typen zu überprüfen, aber ich bin zu faul
            part = MIMEBase('application', "octet-stream")
            part.set_payload( open(file,"rb").read() )
            Encoders.encode_base64(part)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
            msg.attach(part)
        # Löschen erstellt Tar
        return msg

if __name__ == '__main__':
    mail = SendMail()
    # Datei senden, die im Kommandozeilen-Argument enthalten ist
    mail.send(sys.argv[1:])
Grüße Nobuddy

Re: Programm aufrufen

Verfasst: Donnerstag 24. Mai 2012, 09:35
von EyDu
Und dann solltest du deinem Modul noch einen Richtigen Namen geben ;-) "__modul_email__" ist gleich doppelt falsch: Zum einen die doppelten Unterstriche und zum anderen das überflüssige "modul" im Namen.

Sebastian

Re: Programm aufrufen

Verfasst: Donnerstag 24. Mai 2012, 11:40
von Leonidas
Und zur Vorwarnung: nenne es nicht "email.py"

Re: Programm aufrufen

Verfasst: Donnerstag 24. Mai 2012, 14:10
von Nobuddy
Hallo zusammen,
meine Namensgebung mit den Unterstrichen und dem Anfangswort 'modul', dient bei mir zur Sortierung in dem betreffenden Ordner, da weitere Dateien dort sich befinden, die wieder eine andere Funktion haben.

Re: Programm aufrufen

Verfasst: Donnerstag 24. Mai 2012, 15:19
von lunar
@Nobuddy: Nicht Dein Ernst, oder? Nutze Pakete und verwende vernünftige Modulnamen, um Deinen Quelltext zu strukturieren.

Re: Programm aufrufen

Verfasst: Freitag 25. Mai 2012, 20:51
von Hyperion
Und nenne nichts `files`, was in Wirklichkeit `filenames` sind ;-) Und `file` sollte man auch aus dem Grund schon nicht nehmen - selbst wenn es sich um ein file-Objekt handelte - da es ein Built-in überschreibt.