[bottle] Formular (mailform)?

Django, Flask, Bottle, WSGI, CGI…
Antworten
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Brauch mal einen Gedankenanstoss für ein einfaches Kontaktformular, welches die Eingaben an eine bestimmte Mailadresse versenden soll. Ich möchte das ganze aber nicht über cgi-bin bzw Perl laufen lassen.

Mittels get-Methode kann ich mir zumindest schon mal die Eingabe auf der Konsole anzeigen lassen:

Code: Alles auswählen

get('/kontakt')
def kontakt():
    if request.GET.get('save','').strip():
        name = request.GET.get('name', '').strip()
        email = request.GET.get('email', '').strip()
        text = request.GET.get('text', '').strip()
    else:
        pass
    print 'Neuer Kontakt: Email', email, name, text
Bin halt noch ein blutiger Anfänger :wink:
deets

dann google doch mal "python send mail" und schau, was bei rumkommt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wichtig ist, das alle reinkommenden Daten validiert werden! Nicht einfach nehmen und an sendmail übergeben, ansonsten hat man schnell eine SPAM Schleuder aufgebaut ;)

Mit Django hat man alles dabei:
* die Daten validieren mit den 'forms': https://docs.djangoproject.com/en/1.4/topics/forms/
* mails verschicken: https://docs.djangoproject.com/en/1.4/topics/email/

Sicherlich kann man auch auf andere Libs zurück greifen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

So was in der Art bräuchte ich:

Code: Alles auswählen

from django.core.mail import send_mail, BadHeaderError

def send_email(request):
    subject = request.POST.get('subject', '')
    message = request.POST.get('message', '')
    from_email = request.POST.get('from_email', '')
    if subject and message and from_email:
        try:
            send_mail(subject, message, from_email, ['admin@example.com'])
        except BadHeaderError:
            return HttpResponse('Invalid header found.')
        return HttpResponseRedirect('/contact/thanks/')
    else:
        # In reality we'd use a form class
        # to get proper validation errors.
        return HttpResponse('Make sure all fields are entered and valid.')
Aber das wird mir wohl bottle nicht bieten (diese Module). Werde mich mal in das Thema einlesen.
BlackJack

@lackschuh: Für die Forms kann man zum Beispiel `wtforms` verwenden. Für's versenden gäbe es `turbomail`.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:


GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

jens hat geschrieben:@lackschuh: Bitte mal das lesen: http://wiki.python.de/Web-Frameworks#We ... w-r_wen.3F
Moin,

das habe ich mir als erstes durchgelesen und mich dann für bottle entschieden. Die Homepage ist soweit ja schon fertig (ca. 15 Seiten mit Sub-Sites). Nur fehlt mir eben noch die Idee, wie ich ein Kontaktformular mit Spamschutz (zB Berechnen Sie 3+5...) erstelle, welches mir die Eingabe an eine bestimmte Mailadresse schickt.
deets

BlackJack sagte es ja schon - benutz turbomail (haette ich selbst auch drauf kommen muessen, hab's schliesslich hier schon oefter erwaehnt...)
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Ich hab mich ein wenig mit den obgenannten Bibliotheken beschäftigt. Nun bin ich aber an dem Pukt angekommen, wo ich wieder ein wenig Hilfe brauche (weil die Dokumentationen sehr spärlich sind).

Mit dem Marrow Mailer (ehemals Turbomail) kann ich schon einmal Mails verschicken:

maildelivery.py

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf -8 -*-
from marrow.mailer import Mailer, Message
import forms


mailer = Mailer(dict(
        transport = dict(
                use = 'smtp',
                host = 'mail.meineDomain.com',
                port = '587',
                username = 'xxxx',
                password = 'xxxx',
                tls = 'required',
                debug = True),
        manager = dict()))
mailer.start()

message = Message(author="", to=u"Mich <info@meineDomain.com>")
message.subject = ""
message.plain = u""
filname = ""
message.attach(filname) 

mailer.send(message)
mailer.stop()
Des Weiteren habe ich mittels WTForms meine Eingabefelder fürs Formular deffiniert
forms.py:

Code: Alles auswählen

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

from wtforms import Form, FileField, TextField, TextAreaField, SubmitField, validators

class AttachmentForm(Form):
    name = TextField(u'Name',
            [validators.Required(
             message=u'Bitte geben Sie einen Namen ein!'),
             validators.Length(max=50,
             message=u'Der Text darf nicht länger als 50 Zeichen\
             sein.')])   

    email = TextField(u'E-Mail',
            [validators.Email(
             message=u'Keine oder falsche E-Mailadresse eingegeben!'),
             validators.Length(max=50,
             message=u'Der Text darf nicht länger als 50 Zeichen\
             sein.')])
    
    betreff = TextField(u'Betreff',
            [validators.Required(
             message=u'Bitte geben Sie einen Betreff an!'),
             validators.Length(max=50,
             message=u'Der Text darf nicht länger als 50 Zeichen\
             sein.')])

    kommentar = TextAreaField(u'Kommentar',
            [validators.Required(
             message=u'Bitte geben Sie Ihre Nachricht ein'),
             validators.Length(max=50,
             message=u'Der Text darf nicht länger als 50 Zeichen\
             sein.')])
         
    attachment = FileField(u'Datei',
        [validators.regexp(r'.+\.(jpg|pdf|png|docx|doc|txt)$',
        flags=2,
        message=u'Es sind nur Dateien mit der Endung jpg, pdf,\
        png, docx, doc und txt erlaubt!')])
    
    send = SubmitField(u'Senden')
Das formular.tpl:

Code: Alles auswählen

<html>
<head>
<title>Kontaktformular</title>
</head>
<body>
<h2>Datei-Upload</h2>
%if errors:
<p class="fehler">Die Eingabe enthält <a href="#fehler">Fehler</a></p>
%end
<p></p>
%if errors:
<p style="color: #ff0000;">Fehler:</p>
%for k,v in errors.iteritems():
<p><b>{{!form[k].label}}</b>: {{!v[0]}}</p>
%end
%end
<form action="/kontakt" method="post" enctype="multipart/form-data">
<ul>
<li>{{!form.name.label()}}<br/> {{!form.name(size=75)}}</li>
<br/>
<li>{{!form.email.label()}}<br/> {{!form.email(size=75)}}</li>
<br/>
<li>{{!form.betreff.label()}}<br/> {{!form.betreff(size=75)}}</li>
<br/>
<li>{{!form.kommentar.label()}}<br/> {{!form.kommentar(size=75)}}</li>
<br/>
<li>{{!form.attachment.label()}}<br/> {{!form.attachment(size=75)}}</li>
</ul>
<p>{{!form.send()}}</p>
</form>
</body>
</html>
Und dann noch die Bottle App
home.py

Code: Alles auswählen

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

import os
from bottle import route, template, request, run, debug, error
import forms
import maildelivery

# Linux Pfad
# static_folder = '/var/www/meineDomain.com/htdocs/attachment'
PATH = 'C:\\Projekte\\Upload\\attachment'

@route('/kontakt')
@route('/kontakt', method='POST')
def kontakt():
    req = request.forms
    data = request.files.get('attachment')
    form = forms.AttachmentForm(req)
    try:
        form.attachment.data = data.filename
    except:
        form.attachment.data = None
    if not req or not form.validate():
        return template('formular.tpl',
            form=form,errors=form.errors)
    else:
        raw = data.file.read()
        with open(os.path.join(PATH, data.filename),'wb') as f:
            f.write(raw)
        return u'Datei {0} erfolgreich verschickt'.format(
            data.filename, form.name.data)




debug(True)
run(reloader=True, host='10.0.2.110', port=8081)
Alle Skripte funktionieren so weit. Meine Frage ist aber nun, wie ich diese miteinander verbinden kann? Das maildelivery.py Skript soll die ausgefüllten Felder des formular.tpl/forms.py an meine E-Mail Adresse senden. An diesem Punkt bin ich momentan mit meinem Latein wieder am Ende.

mfg
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die Textdaten aus dem Formular musst du halt als Inhalt in deine E-Mail schreiben und die Datei als Anhang anhängen. Wie das geht findest du ziemlich sicher in der Doku von Marrow Mailer.

Gruß, noisefloor
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

noisefloor hat geschrieben:Hallo,

die Textdaten aus dem Formular musst du halt als Inhalt in deine E-Mail schreiben und die Datei als Anhang anhängen. Wie das geht findest du ziemlich sicher in der Doku von Marrow Mailer.

Gruß, noisefloor
Hallo

Also in der Doku - wenn man das überhaupt als Doku bezeichnen kann - hab ich nichts gefunden. Aber auch egal. Ich bin nun ein ganzes Stück weiter gekommen.

Ein paar Fragen hätte ich dennoch:

1: habe ich noch ein ascii Problem mit Umlauten etc:

Code: Alles auswählen

Error 500: Internal Server Error

Sorry, the requested URL 'http://localhost:8081/kontakt' caused an error:

Internal Server Error

Exception:

UnicodeDecodeError('ascii', '\xc3\xbc', 0, 1, 'ordinal not in range(128)')

Traceback:

Traceback (most recent call last):
  File "C:\Projekte\Kontaktformular\bottle.py", line 651, in _handle
    return callback(**args)
  File "C:\Projekte\Kontaktformular\bottle.py", line 1145, in wrapper
    rv = callback(*a, **ka)
  File "home.py", line 31, in kontakt
    form=form,errors=form.errors)
  File "C:\Projekte\Kontaktformular\bottle.py", line 2419, in template
    return TEMPLATES[tpl].render(kwargs)
  File "C:\Projekte\Kontaktformular\bottle.py", line 2393, in render
    self.execute(stdout, kwargs)
  File "C:\Projekte\Kontaktformular\bottle.py", line 2380, in execute
    eval(self.co, env)
  File "kontakt2.tpl", line 37, in <module>
    {{!form.kommentar(class_="imp")}} <br /></td>
  File "C:\Python27\lib\site-packages\wtforms\fields\core.py", line 136, in __call__
    return self.widget(self, **kwargs)
  File "C:\Python27\lib\site-packages\wtforms\widgets\core.py", line 221, in __call__
    return HTMLString(u'<textarea %s>%s</textarea>' % (html_params(name=field.name, **kwargs), escape(unicode(field._value()))))
  File "C:\Python27\lib\site-packages\wtforms\fields\core.py", line 477, in _value
    return unicode(self.data) if self.data is not None else u''
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Wo könnte der Fehler hier liegen?

Und die andere Frage ist, ob der Aufbau des Skrips überhaupt so richtig ist. Hier mal die Bottle-App:

Code: Alles auswählen

@route('/kontakt')
@route('/kontakt', method='POST')
def kontakt():

    req = request.forms
    form = forms.KontaktFormular(req)
    
    
    
    if not req or not form.validate():
        return template('auswahl2.tpl',
            form=form,errors=form.errors)
    else:
        maildelivery.mailer.start()
        message = Message(author="From: '{0}' <{1}>" .format(form.name.data, form.email.data), to=u"Mein Name<meine@domain.com>")
        message.subject = u'{0}'.format(form.betreff.data)
        message.plain = u'{0}'.format(form.kommentar.data)
        
    
        maildelivery.mailer.send(message)
        maildelivery.mailer.stop()
        return u'Hallo {0}, die Nachricht wurde erfolgreich übermittelt.'.format(form.name.data)
Und das marrow.mailer Skript namens maildelivery.py

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf -8 -*-
from marrow.mailer import Mailer, Message
import forms


mailer = Mailer(dict(
        transport = dict(
                use = 'smtp',
                host = 'mail.meineDomain.com',
                port = '587',
                username = 'xxxxxx',
                password = 'xxxxxx',
               # tls = 'required',
                debug = True),
        manager = dict()))
Das Versenden der Daten geht relativ Lange im Vergleich zu meinem Contao CMS. Oder liegt es nur daran, dass ich Bottle z.Z noch lokal laufen habe und noch nicht auf dem Server?

EDIT:

Hier noch ein Auszug aus dem Template:

Code: Alles auswählen

<tr>
          <td><strong>{{!form.name.label()}}</strong><br />
            {{!form.name(class_="imp")}} <br /></td>
          
          <td><strong>{{!form.email.label()}}</strong><br />
            {{!form.email(class_="imp")}}</td>
        </tr>
mfg
Zuletzt geändert von lackschuh am Mittwoch 13. Juni 2012, 08:39, insgesamt 2-mal geändert.
deets

Ich wuerde mal sagen du benutzt Marrow Mailer falsch - das permanente gestarte und gestoppe ist so bestimmt nicht gedacht, und verzoegert im Zweifel sehr. Starte einmal bei Start der Applikation, und das mit dem Stop... ka ob bottle einen Mechanismus kennt das herunterfahren der Anwendung mit einem Event oder Callback oder so zu versehen.

Den UnicodeDecodeError finde ich komisch, haette gedacht, bottle liefert nur unicode und Marrow encodiert das proper. Aber wahrscheinlich benutzt du diese forms falsch.
Antworten