I have the logging module MemoryHandler set up to queue debug and error messages for the SMTPHandler target. What I want is for an email to be sent when the process errors that contains all debug statements up to that point (one per line). What I get instead is a separate email for every debug message.
This seems like it should be trivial, and part of the logging package, but I can't find anything about it, no examples, nothing on Google.
log = logging.getLogger()
log.setLevel(logging.DEBUG)
debug_format = logging.Formatter("%(levelname)s at %(asctime)s in %(filename)s (line %(lineno)d):: %(message)s")
# write errors to email
error_mail_subject = "ERROR: Script error in %s on %s" % (sys.argv[0], os.uname()[1])
error_mail_handler = logging.handlers.SMTPHandler(SMTP_HOST, 'errors#'+os.uname()[1], [LOG_EMAIL], error_mail_subject)
error_mail_handler.setLevel(logging.ERROR)
#error_mail_handler.setLevel(logging.DEBUG)
error_mail_handler.setFormatter(debug_format)
# buffer debug messages so they can be sent with error emails
memory_handler = logging.handlers.MemoryHandler(1024*10, logging.ERROR, error_mail_handler)
memory_handler.setLevel(logging.DEBUG)
# attach handlers
log.addHandler(memory_handler)
log.addHandler(error_mail_handler)
Related to this:
Do I need to add the error_mail_handler to the logger explicitly if it is a target of memory_handler anyway?
Should error_mail_handler be set to DEBUG or ERROR target? Does it even need a target when it is being fed from memory_handler?
Would love to see some working code from anyone who has solved this problem.
You might want to use or adapt the BufferingSMTPHandler which is in this test script.
In general, you don't need to add a handler to a logger if it's the target of a MemoryHandler handler which has been added to a logger. If you set the level of a handler, that will affect what the handler actually processes - it won't process anything which is less severe than its level setting.
Instead of buffering for email, consider posting unbuffered to a message stream on a messaging app, e.g. on Matrix, Discord, Slack, etc. Having said that, I wrote my own beastly thread-safe implementation of BufferingSMTPHandler (backup link) which sends emails from a separate thread. The primary goal is to not block the main thread.
As written, it uses two queues - this seemed necessary in order to implement some useful class-level parameters that are defined in the "Configurable parameters" section of the code. Although you can use the code as-is, it's probably better if you study and use it to write your own class.
Issues:
Some class-level parameters can perhaps be instance-level instead.
Either threading.Timer or the signal module could perhaps be used to avoid loops that run forever.
If you are using django - here is simple buffering handler, which will use standard django email methods:
import logging
from django.conf import settings
from django.core.mail import EmailMessage
class DjangoBufferingSMTPHandler(logging.handlers.BufferingHandler):
def __init__(self, capacity, toaddrs=None, subject=None):
logging.handlers.BufferingHandler.__init__(self, capacity)
if toaddrs:
self.toaddrs = toaddrs
else:
# Send messages to site administrators by default
self.toaddrs = zip(*settings.ADMINS)[-1]
if subject:
self.subject = subject
else:
self.subject = 'logging'
def flush(self):
if len(self.buffer) == 0:
return
try:
msg = "\r\n".join(map(self.format, self.buffer))
emsg = EmailMessage(self.subject, msg, to=self.toaddrs)
emsg.send()
except Exception:
# handleError() will print exception info to stderr if logging.raiseExceptions is True
self.handleError(record=None)
self.buffer = []
In django settings.py you will need to configure email and logging like this:
EMAIL_USE_TLS = True
EMAIL_PORT = 25
EMAIL_HOST = '' # example: 'smtp.yandex.ru'
EMAIL_HOST_USER = '' # example: 'user#yandex.ru'
EMAIL_HOST_PASSWORD = ''
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USER
LOGGING = {
'handlers': {
...
'mail_buffer': {
'level': 'WARN',
'capacity': 9999,
'class': 'utils.logging.DjangoBufferingSMTPHandler',
# optional:
# 'toaddrs': 'admin#host.com'
# 'subject': 'log messages'
}
},
...
}
For this purpose I use the BufferingSMTPHandler suggested by Vinay Sajip with one minor tweak: I set the buffer length to something really big (say 5000 log records) and manualy call the flush method of the handler every some seconds and after checking for internet conectivity.
# init
log_handler1 = BufferingSMTPHandler(
'smtp.host.lala', "from#test.com", ['to#test.com'], 'Log event(s)',5000)
...
logger.addHandler(log_handler1)
...
# main code
...
if internet_connection_ok and seconds_since_last_flush>60:
log_handler1.flush() # send buffered log records (if any)
Updated Vinay Sajip's answer for python3.
import logging
from logging.handlers import BufferingHandler
class BufferingSMTPHandler(BufferingHandler):
def __init__(self, mailhost, fromaddr, toaddrs, subject, capacity):
logging.handlers.BufferingHandler.__init__(self, capacity)
self.mailhost = mailhost
self.mailport = None
self.fromaddr = fromaddr
self.toaddrs = toaddrs
self.subject = subject
self.setFormatter(logging.Formatter("%(asctime)s %(levelname)-5s %(message)s"))
def flush(self):
if len(self.buffer) > 0:
try:
import smtplib
port = self.mailport
if not port:
port = smtplib.SMTP_PORT
smtp = smtplib.SMTP(self.mailhost, port)
msg = '''From: {}\r\nTo: {}\r\nSubject: {}\r\n\r\n'''.format(
self.fromaddr,
",".join(self.toaddrs),
self.subject
)
for record in self.buffer:
s = self.format(record)
print (s)
msg = msg + s + "\r\n"
smtp.sendmail(self.fromaddr, self.toaddrs, msg)
smtp.quit()
except:
self.handleError(None) # no particular record
self.buffer = []
#update for #Anant
if __name__ == '__main__'
buff_smtp_handler=BufferingSMTPHandler(...your args)
buff_smtp_handler.setLevel(logging.ERROR)
handlers=[buff_smtp_handler]
logging.basicConfig(handlers=handlers)
I think the point about the SMTP logger is that it is meant to send out a significant log message functioning as some kind of alert if sent to a human recipient or else to be further processed by an automated recipient.
If a collection of log messages is to be sent by email then that constitutes a report being sent at the end of execution of a task and writing that log to a file and then emailing the file would seem to be a reasonable solution.
I took a look at the basic FileHandler log handler and how to build a mechanism to write to a temp file then attach that temp file when the script exits.
I found the "atexit" module that allows for a method to be registered that will be executed against an object when the script is exiting.
import logging
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
import os
from email import encoders
import uuid
# atexit allows for a method to be set to handle an object when the script exits
import atexit
filename = uuid.uuid4().hex
class MailLogger:
def __init__(self, filePath, smtpDict):
self.filePath = filePath
self.smtpDict = smtpDict
# Generate random file name
filename = '%s.txt' % ( uuid.uuid4().hex )
# Create full filename
filename = '%s/%s' % (filePath,filename)
self.filename = filename
self.fileLogger = logging.getLogger('mailedLog')
self.fileLogger.setLevel(logging.INFO)
self.fileHandler = logging.FileHandler(filename)
self.fileHandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
self.fileHandler.setFormatter(formatter)
self.fileLogger.addHandler(self.fileHandler)
atexit.register(self.mailOut)
def mailOut(self):
'''
Script is exiting so time to mail out the log file
"emailSettings": {
"smtpServer" : "smtp.dom.com",
"smtpPort" : 25,
"sender" : "sender#dom.com>",
"recipients" : [
"recipient#dom.com"
],
"subject" : "Email Subject"
},
'''
# Close the file handler
smtpDict = self.smtpDict
self.fileHandler.close()
msg = MIMEMultipart('alternative')
s = smtplib.SMTP(smtpDict["smtpServer"], smtpDict["smtpPort"] )
msg['Subject'] = smtpDict["subject"]
msg['From'] = smtpDict["sender"]
msg['To'] = ','.join(smtpDict["recipients"])
body = 'See attached report file'
content = MIMEText(body, 'plain')
msg.attach(content)
attachment = MIMEBase('application', 'octet-stream')
attachment.set_payload(open(self.filename, 'rb').read())
encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(self.filename))
msg.attach(attachment)
s.send_message(msg)
s.quit()
My basic test script is:
from EmailLogRpt import MailLogger
import time
smtpDict = {
"smtpServer" : "smtp.dom.com",
"smtpPort" : 25,
"sender" : "sender#dom.com",
"recipients" : [
"recpient#dom.com>"
],
"subject" : "Email Subject"
}
myMailLogger = MailLogger("/home/ed/tmp",smtpDict).fileLogger
myMailLogger.info("test msg 1")
time.sleep(5)
myMailLogger.info("test msg 2")
Hope this helps somebody.
Related
I have a need to take an incoming email that matches a specific ruleset in postfix, send it to an external python process, rewrite the email to multiple delivery recipients based upon the postfix postmap table, and re-inject back into the postfix chain. The included python meets that basic requirement except for one, tracking the queueid of the new re-injected email.
The typical method of re-injecting with /usr/sbin/sendmail does not return a usable queueid for the correct process. This causes loss of visibility of the newly created emails (logs have to be manually parse to generate a delivery confirmation report for 3rd parties).
Since the re-injection process is in python, ideally I would like to use the smtplib.Sendmail for that, but it also does not return a queueid.
What I have tried, and kind of works, is using netcat as a subprocess in python (netcat_msg = "helo myserver\nmail from: " + sender + "\nrcpt to: " + recipient + "\ndata\n" + msg.as_string() + "\n\n.\nquit\n") but I feel that's a hack and I get warnings about command sequences in smtp (which is expected since I'm not waiting on the response before issuing the next command).
Is there a way to expose the queueid returned from the remote SMTP server when the process completes? Any recommended approaches to this?
My goal is to log these queueids to a file/api endpoint/whatever so we can determine that incoming email to a#domain.tld was sent to bob#example.com, chris#example.com and track the return status of the destination server.
(Excuse my crude python)
#!/bin/python
#v 2.7.15
import email
import sys
from email.mime.text import MIMEText
import argparse
from subprocess import Popen
from subprocess import PIPE
#ignore this, it was just for debugging
def dump(obj):
for attr in dir(obj):
if hasattr( obj, attr ):
print( "obj.%s = %s" % (attr, getattr(obj, attr)))
def process_message(data, sender, recipient):
msg = email.message_from_string(data)
newaddress = '"{recipient}" <{recipient}>'.format(recipient=recipient)
oldaddress = ''
if msg.has_key('To'):
oldaddress = msg['To']
msg.replace_header('To', newaddress)
else:
msg.add_header('To', newaddress)
oldaddress = newaddress
if msg.has_key('X-Original-To'):
msg.replace_header('X-Original-To', oldaddress)
else:
msg.add_header('X-Original-To', oldaddress)
#print(msg.as_string())
try:
# replace this with a re-inject that can return the queueid
p = Popen(["/usr/sbin/sendmail", "-G", "-i", "-f " + sender, "--", recipient ], stdin=PIPE)
p.communicate(msg.as_string())
# end replacement
# log original queueid, returned queueid and destination email here
except Exception as ex:
exit(69)
def main():
parser = argparse.ArgumentParser(description='To field replacement for Email MIME.')
parser.add_argument('--from', dest="sender", help="From email address", required=True)
parser.add_argument('--recipient', dest="recipients", help="Recipient address to replace in To field (N+1)", nargs='+', required=True)
args = parser.parse_args()
#dump(args)
data = sys.stdin.readlines()
data = ''.join(data)
for recipient in args.recipients:
#print(recipient)
process_message(data, args.sender, recipient)
exit(0)
main()
first, I'm sorry about my low level english
I create a website for study
I create send SMS feature using django + redis + celery
tasks/send_buy_sms.py
from celery import Task
from items.utils import SendSMS
class SendBuyMessageTask(Task):
def run(self, buyer_nickname, buyer_phone, saler_phone, selected_bookname):
sms = SendSMS()
sms.send_sms(buyer_nickname, buyer_phone, saler_phone, selected_bookname)
items/utils.py
import os
import requests
import json
class SendSMS():
def send_sms(self, buyer_nickname, buyer_phone, saler_phone, selected_bookname):
appid = [...]
apikey = [...]
sender = '...'
receivers = [saler_phone, ]
content = '...'
url = os.environ.get("URL")
params = {
'sender': sender,
'receivers': receivers,
'content': content,
}
headers = {...}
r = '...'
return params
when I send sms using my code it has no problem
[2017-09-12 17:20:43,532: WARNING/Worker-6] Task success
and I want make log file and insert log "success send SMS" when user click "send sms button"
wef/wef/decorators.py
from django.utils import timezone
import logging
def log_decorator(func):
logging.basicConfig(filename='../../sendsms.log', level=logging.INFO)
def wrap_func(self, *args, **kwargs):
time_stamp = timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M')
logging.info('[{}] success send SMS'.format(time_stamp))
print(logging)
return func(self, *args, **kwargs)
return wrap_func
but when I click 'send sms' button task is Ok , but log file doesn't created...
So I want to know 'what is the problem?'
I change my code create logfile -> print log
wef/wef/decorators.py
from django.utils import timezone
def log_decorator(func):
def wrap_func(self, *args, **kwargs):
time_stamp = timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M')
## print log
print('[{}] succes send sms'.format(timestamp))
## print log
return func(self, *args, **kwargs)
return wrap_func
when I click 'send sms button' the log print in celery
I'm so confused because print() is working but create log file doesn't working...
I think my code(create logging file) is no problem because when I practice create log file without django,celery,redis, log file was created successfully
same code, same feature but not working in django and celery
please give me some advise thank you
I guess you have to add logger like -
# import the logging library
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
def my_view(request, arg1, arg):
...
if bad_mojo:
# Log an error message
logger.error('Something went wrong!')
Here I am assuming that you have configured your loggers, handlers, filters and formatters
For more information visit URL
In my python script, I am using the logging module with INFO going to a file and the screen:
fh_info = logging.FileHandler(info)
fh_info.setLevel(logging.INFO)
fh_info.setFormatter(formatter)
std_out_info = logging.StreamHandler()
std_out_info.setLevel(logging.INFO)
logger.addHandler(fh_info)
logger.addHandler(std_out_info)
But the issue I am having is that the messages got to the screen after the function is completed. For instance, in:
def getToken(self):
msg = ("Initializing token....")
logger.info(msg)
sys.stdout.flush()
try:
jsonreq = ( {"auth": {"KEY:apiKeyCredentials": {
"username": self.username,
"apiKey": self.apikey}}})
auth_headers = {'content-type': 'application/json'}
r = requests.post(self.url, data=json.dumps(jsonreq), headers=auth_headers)
self.jsonresp = json.loads(r.text)
self.token = str(self.jsonresp['access']['token']['id'])
msg = ("done!")
logger.info(msg)
except:
msg = ("Bad name or apikey!")
logger.error(msg)
sys.exit()
The message "Initializing token...." will go to the screen after the operations in the function are completed. The makes for a long pause while authentication is going on with no output...then after authentication completes I see "Initializing token....done".
How can I make the logger.info(msg) stay in sync with the flow of the script and output to the screen in it's timely manner?
You are not initialising the StreamHandler with sys.stdout, so it will use the documented default - sys.stderr. That's why your flushing of sys.stdout isn't having any effect - there's nothing the the code you posted which is causing writes to sys.stdout!
I'm currently trying to add PGP signing support to my small e-mail sending script (which uses Python 3.x and python-gnupg module).
The code that signs message is:
gpg = gnupg.GPG()
basetext = basemsg.as_string().replace('\n', '\r\n')
signature = str(gpg.sign(basetext, detach=True))
if signature:
signmsg = messageFromSignature(signature)
msg = MIMEMultipart(_subtype="signed", micalg="pgp-sha1",
protocol="application/pgp-signature")
msg.attach(basemsg)
msg.attach(signmsg)
else:
print('Warning: failed to sign the message!')
(Here basemsg is of email.message.Message type.)
And messageFromSignature function is:
def messageFromSignature(signature):
message = Message()
message['Content-Type'] = 'application/pgp-signature; name="signature.asc"'
message['Content-Description'] = 'OpenPGP digital signature'
message.set_payload(signature)
return message
Then I add all the needed headers to the message (msg) and send it.
This works well for non-multipart messages, but fails when basemsg is multipart (multipart/alternative or multipart/mixed).
Manually verifying the signature against the corresponding piece of text works, but Evolution and Mutt report that the signature is bad.
Can anybody please point me to my mistake?
The problem is that Python's email.generator module doesn't add a newline before the signature part. I've reported that upstream as http://bugs.python.org/issue14983.
(The bug was fixed in Python2.7 and 3.3+ in 2014)
What is actually the MIME structure of basemsg? It appears that it has too many nested parts in it. If you export a signed message from e.g. Evolution, you'll see that it has just two parts: the body and the signature.
Here's an example which generates a message on stdout that can be read and the signature verified on both mutt (mutt -f test.mbox) and Evolution (File -> Import).
import gnupg
from email.message import Message
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
body = """
This is the original message text.
:)
"""
gpg_passphrase = "xxxx"
basemsg = MIMEText(body)
def messageFromSignature(signature):
message = Message()
message['Content-Type'] = 'application/pgp-signature; name="signature.asc"'
message['Content-Description'] = 'OpenPGP digital signature'
message.set_payload(signature)
return message
gpg = gnupg.GPG()
basetext = basemsg.as_string().replace('\n', '\r\n')
signature = str(gpg.sign(basetext, detach=True, passphrase=gpg_passphrase))
if signature:
signmsg = messageFromSignature(signature)
msg = MIMEMultipart(_subtype="signed", micalg="pgp-sha1",
protocol="application/pgp-signature")
msg.attach(basemsg)
msg.attach(signmsg)
msg['Subject'] = "Test message"
msg['From'] = "sender#example.com"
msg['To'] = "recipient#example.com"
print(msg.as_string(unixfrom=True)) # or send
else:
print('Warning: failed to sign the message!')
Note that here, I'm assuming a keyring with a passphrase, but you may not need that.
There are much more problem with the python built-in email library.
If you call the as_string procedure, the headers will be scanned for maxlinelength only in the current class, and in the childs (_payload) not! Like this:
msgRoot (You call `to_string` during sending to smtp and headers will be checked)
->msgMix (headers will be not checked for maxlinelength)
-->msgAlt (headers will be not checked for maxlinelength)
--->msgText (headers will be not checked for maxlinelength)
--->msgHtml (headers will be not checked for maxlinelength)
-->msgSign (headers will be not checked for maxlinelength)
I have signed msgMix.to_string() and then attached the signed message to the msgRoot. But during sending to the SMTP the msgMix part was different, the headers in msgMix was not chucked. Ofc, the sign was invalid.
It has taken two days for me to understand everything.. Here is my code what works and I use for sending automatic emails:
#imports
import smtplib, gnupg
from email import Charset, Encoders
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.message import Message
from email.generator import _make_boundary
#constants
EMAIL_SMTP = "localhost"
EMAIL_FROM = "Fusion Wallet <no-reply#fusionwallet.io>"
EMAIL_RETURN = "Fusion Wallet Support <support#fusionwallet.io>"
addr = 'some_target_email#gmail.com'
subject = 'test'
html = '<b>test</b>'
txt = 'test'
#character set
Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')
#MIME handlers
msgTEXT = MIMEText(txt, 'plain', 'UTF-8')
msgHTML = MIMEText(html, 'html', 'UTF-8')
msgRoot = MIMEMultipart(_subtype="signed", micalg="pgp-sha512", protocol="application/pgp-signature")
msgMix = MIMEMultipart('mixed')
msgAlt = MIMEMultipart('alternative')
msgSIGN = Message()
msgOWNKEY = MIMEBase('application', "octet-stream")
#Data
msgRoot.add_header('From', EMAIL_FROM)
msgRoot.add_header('To', addr)
msgRoot.add_header('Reply-To', EMAIL_FROM)
msgRoot.add_header('Reply-Path', EMAIL_RETURN)
msgRoot.add_header('Subject', subject)
msgMix.add_header('From', EMAIL_FROM)
msgMix.add_header('To', addr)
msgMix.add_header('Reply-To', EMAIL_FROM)
msgMix.add_header('Reply-Path', EMAIL_RETURN)
msgMix.add_header('Subject', subject)
msgMix.add_header('protected-headers', 'v1')
#Attach own key
ownKey = gpg.export_keys('6B6C0EBB6DC42AA4')
if ownKey:
msgOWNKEY.add_header("Content-ID", "<0x6B6C0EBB.asc>")
msgOWNKEY.add_header("Content-Disposition", "attachment", filename='0x6B6C0EBB.asc')
msgOWNKEY.set_payload(ownKey)
#Attaching
msgAlt.attach(msgTEXT)
msgAlt.attach(msgHTML)
msgMix.attach(msgAlt)
if ownKey:
msgMix.attach(msgOWNKEY)
#Sign
gpg = gnupg.GPG()
msgSIGN.add_header('Content-Type', 'application/pgp-signature; name="signature.asc"')
msgSIGN.add_header('Content-Description', 'OpenPGP digital signature')
msgSIGN.add_header("Content-Disposition", "attachment", filename='signature.asc')
originalSign = gpg.sign(msgMix.as_string().replace('\n', '\r\n').strip()).data
spos = originalSign.index('-----BEGIN PGP SIGNATURE-----')
sign = originalSign[spos:]
msgSIGN.set_payload(sign)
#Create new boundary
msgRoot.set_boundary(_make_boundary(msgMix.as_string()))
#Set the payload
msgRoot.set_payload(
"--%(boundary)s\n%(mix)s--%(boundary)s\n%(sign)s\n--%(boundary)s--\n" % {
'boundary':msgRoot.get_boundary(),
'mix':msgMix.as_string(),
'sign':msgSIGN.as_string(),
}
)
#Send to SMTP
s = smtplib.SMTP(EMAIL_SMTP)
s.sendmail(EMAIL_FROM, addr, msgRoot.as_string())
s.quit()
I'm using an open source web service python application to send email through GAE but if the name or email body contains Arabic or Hebrew characters the application throws some errors (e.g "The indicated parameters are not valid"). Therefore I need to know how to fix this issue. I have to note that I'm a Python beginner (one week since I started playing with Python).
#
import cgi
import os
import logging
import contextlib
from xml.dom import minidom
from xml.dom.minidom import Document
import exceptions
import warnings
import imghdr
from google.appengine.api import images
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.api import mail
import wsgiref.handlers
# START Constants
CONTENT_TYPE_HEADER = "Content-Type"
CONTENT_TYPE_TEXT = "text/plain"
XML_CONTENT_TYPE = "application/xml"
XML_ENCODING = "utf-8"
"""
Allows you to specify IP addresses and associated "api_key"s to prevent others from using your app.
Storage and Manipulation methods will check for this "api_key" in the POST/GET params.
Retrieval methods don't use it (however you could enable them to use it, but maybe rewrite so you have a "read" key and a "write" key to prevent others from manipulating your data).
Set "AUTH = False" to disable (allowing anyone use your app and CRUD your data).
To generate a hash/api_key visit https://www.grc.com/passwords.htm
To find your ip visit http://www.whatsmyip.org/
"""
AUTH = False
# END Constants
# START Exception Handling
class Error(StandardError):
pass
class Forbidden(Error):
pass
logging.getLogger().setLevel(logging.DEBUG)
#contextlib.contextmanager
def mailExcpHandler(ctx):
try:
yield {}
except (ValueError), exc:
xml_error_response(ctx, 400 ,'app.invalid_parameters', 'The indicated parameters are not valid: ' + exc.message)
except (Forbidden), exc:
xml_error_response(ctx, 403 ,'app.forbidden', 'You don\'t have permission to perform this action: ' + exc.message)
except (Exception), exc:
xml_error_response(ctx, 500 ,'system.other', 'An unexpected error in the web service has happened: ' + exc.message)
def xml_error_response(ctx, status, error_id, error_msg):
ctx.error(status)
doc = Document()
errorcard = doc.createElement("error")
errorcard.setAttribute("id", error_id)
doc.appendChild(errorcard)
ptext = doc.createTextNode(error_msg)
errorcard.appendChild(ptext)
ctx.response.headers[CONTENT_TYPE_HEADER] = XML_CONTENT_TYPE
ctx.response.out.write(doc.toxml(XML_ENCODING))
# END Exception Handling
# START Helper Methods
def isAuth(ip = None, key = None):
if AUTH == False:
return True
elif AUTH.has_key(ip) and key == AUTH[ip]:
return True
else:
return False
# END Helper Methods
# START Request Handlers
class Send(webapp.RequestHandler):
def post(self):
"""
Sends an email based on POST params. It will queue if resources are unavailable at the time.
Returns "Success"
POST Args:
to: the receipent address
from: the sender address (must be a registered GAE email)
subject: email subject
body: email body content
"""
with mailExcpHandler(self):
# check authorised
if isAuth(self.request.remote_addr,self.request.POST.get('api_key')) == False:
raise Forbidden("Invalid Credentials")
# read data from request
mail_to = str(self.request.POST.get('to'))
mail_from = str(self.request.POST.get('from'))
mail_subject = str(self.request.POST.get('subject'))
mail_plain = str(self.request.POST.get('plain'))
mail_html = str(self.request.POST.get('html'))
message = mail.EmailMessage()
message.sender = mail_from
message.to = mail_to
message.subject = mail_subject
message.body = mail_plain
if mail_html != None and mail_html != "":
message.html = mail_html
message.send()
self.response.headers[CONTENT_TYPE_HEADER] = CONTENT_TYPE_TEXT
self.response.out.write("Success")
# END Request Handlers
# START Application
application = webapp.WSGIApplication([
('/send', Send)
],debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()
# END Application
mail_to = str(self.request.POST.get('to'))
mail_from = str(self.request.POST.get('from'))
mail_subject = str(self.request.POST.get('subject'))
mail_plain = str(self.request.POST.get('plain'))
mail_html = str(self.request.POST.get('html'))
I doubt you need to convert them to strings. Try without str(), it could work.