Posts about programming (old posts, page 16)

2008-06-26 14:56

Creating and sending nice HTML+Text mails from python

I decided I needed an automatic report of some things on my email every day, and I wanted it to look nice both in plain text and HTML. Here's what I came up with.

Let's assume you created the HTML version using whatever mechanism you wish, and have it in a variable called "report".

Here's the imports we will use:

import smtplib,email,os,tempfile
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.Charset import Charset

And here's the code:

# Create a HTML mail part
hpart=MIMEText(reporte, _subtype='html', _charset='utf-8')

# Create a plain text mail part
# Ugly and requires links, but makes for a great-looking plain text version ;-)
tf=tempfile.mkstemp()
t=open(tf,'w')
t.write(report)
t.close()
tpart=MIMEText(os.popen('links -dump %s'%tf,'r').read(), _subtype='plain', _charset='utf-8')
os.unlink(tf)

# Create the message with both parts attached
msg=MIMEMultipart('alternative')
msg.attach(hpart)
msg.attach(tpart)

# Standard headers (add all you need, for example, date)
msg['Subject'] = 'Report'
msg['From']    = '[email protected]'
msg['To']      = '[email protected]'

#If you need to use SMTP authentication, change accordingly
smtp=smtplib.SMTP('mail.yourcompany.com'')
smtp.sendmail('[email protected]','[email protected]',msg.as_string())

2008-06-20 14:23

Adding MSN notifications to Argus

I am a user of Argus as a monitoring software. Since it's very flexible and easy to extend, I wanted to add MSN alerts, the same way I had added SMS alerts a while ago. It was easier than I thought!

  1. Install msnlib

  2. Install the example msnbot, modified so do_work is like this:

    def do_work():
       """
       Here you do your stuff and send messages using m.sendmsg()
       This is the only place your code lives
       """
    
       # wait a bit for everything to settle down (sync taking efect
       # basically)
       time.sleep(15)
    
       msg=sys.stdin.read()
       for d in sys.argv[3].split('+'):
               print m.sendmsg(d,msg)
    
    
       # give time to send the messages
       time.sleep(30)
    
       # and then quit
       quit()
    
  3. Define a custom notification in argus like this:

    Method "msn" {
       command: /usr/local/bin/msnbot [email protected] mypass %R >/tmp/XXX 2>&1
       send: %M\n
    }
    
  4. Wherever you want MSN notifications, add this (on notify or escalate directives, using as many guys MSN addresses as you need):

    msn:[email protected][email protected]
    

That's it.

2008-06-16 22:27

Kid, wanna try a WM?

Reading a post on planetkde, I saw an apparently out-of-nowhere reference to blackboxqt...

Not all that interesting, I suppose, but I am fond of ol'BB,and this Qt4 remake could be pretty cool (although I can't test it because it doesn't build for me). Here's a link to the code.

2008-04-23 22:20

My first impressions of Google App Engine

Since I got my invitation and am tired of Haloscan not being reachable from home (not their fault, probably), I decided that my first project would be a comment hosting app.

In other words, something a bit HaloScan-like.

Since I have very limited resources, it will probably not be useful for many people, but I am learning about App Engine, and at the same time probably making my blog a wee bit more comfortable.

Some random thoughts:

  • Can I put Google ads in app engine apps?
  • Does anyone else need this kind of app? I intend to make it open, so anyone can register its blog in it and use it. 500MB (the max DB size) are a lot of comments. Like a million of them.
  • I intend to use Yahoo's YUI RTE for editing. So my app will be hosted in Yahoo and Google. Cool :-D
  • It's basically just Django. Sure, no UNIQUE, no CRUD (ok, there is Google's, which is kinda lame... hire one of the Django guys and mke him work on it ;-), but it's the same thing, give or take a few bytes, specially using djangoforms.
  • webapp is... ok, it's rather ugly. Routing the requests is annoying, you can't do things like passing parts of the URL as parameters...
  • The User/DataStore APIs are ok, they feel a bit limited but they have a lot of scope in other ways (as in, there are a few million registered users and many TB of data stored ;-)

All things considered, a nice thing to use, specially at the cost.

2008-04-15 16:14

Linux as a windows crutch: Sending SMS

Suppose you want to send SMS messages from windows through a bluetooth connection to a phone.

I am sure you can make it work. On the other hand, I already had it working on Linux... so you can just use this on a friendly Linux box, and send SMS messages by accessing a special URL:

#!/usr/bin/env python
from colubrid import BaseApplication, HttpResponse, execute
import os

class SMSApplication(BaseApplication):

  def process_request(self):
      numero = self.request.args.get('numero')
      mensaje = self.request.args.get('mensaje')
      [entrada,salida]=os.popen4('/usr/bin/gnokii --sendsms %s'%numero,mode='rw')
      entrada.write(mensaje)
      entrada.flush()
      entrada.close()
      msg=salida.read()
      response = HttpResponse(msg)
      response['Content-Type'] = 'text/plain'
      return response

if __name__ == '__main__':
  execute(SMSApplication,debug=True, hostname='mybox.domain.internal', port=8080,reload=True)

If someone opens http://mybox.domain.internal:8080/?numero=1234?mensaje=hola%20mundo it sends "hola mundo" to the 1234 number.

I suppose I could call this a web telephony service or somesuch, but it's actually just the 5'solution that came to mind.

It uses a silly little not-a-web-framework called colubrid instead of something you may know, because I wanted to keep it simple, and it doesn't get much simpler than this.

2008-04-09 14:06

A simple memcache memoizer for python>=2.2

Just a snippet of code because every once in a while I need something like the classic memoize decorator but am working on a CentOS 4 bix (with python 2.3!)

I am still testing it, and am not even sure it really works, but it should be close.

cache=memcache.Client(['127.0.0.1:11211'], debug=0)
cachetimeout=30

def memoize(fun):
    def inner(*args, **kwargs):
        key=repr(fun)+repr(args)+repr(kwargs)
        cached = cache.get(key)
        if cached is None:
            val = fun(*args, **kwargs)
            print "Setting: ",key, "to: ",val
            cache.set(key,val,cachetimeout)
            return val
        return cached
    return inner

And later inside a class:

def myfun(self,arg):
   :
   :
myfun=memoize(myfun)

And that's it. The basic idea I stole from a blog who was inspired by a Paul Graham book. It can be trivially turned into a decorator, of course (but then only works on 2.4 and later).

2008-03-09 12:54

Playing with GIT

The guys at http://github.com have been nice enough to add me to their beta program, so I am doing a little project there, to figure out if I like git or not.

Since everyone raves about it, I suppose I will, and then will have to turn my numerous googlecode SVN repos into git mirrors or whatever the correct terminology is.

2008-03-07 07:43

New qmail plugin idea: overload

It should not happen but it does: Your qmail server is overloaded. Maybe you are under a DOS attack, or there is a reason why you are getting 10x your usual amount of mail.

But then you start seeing how your "not preprocessed" queue starts growing, and growing...

This can also mean things like clamav or spamassassin, which need to check the mail before it gets queued are not keeping up with the mail flow, or maybe some IO performace issue.

But what can you do righ now to fix it?

Well, you can disable spamassassin, or, in extreme cases, shutdown SMTP so the system has a chance to catch its breath so to speak.

Of course, closing SMTP means your own users can't send email either, which sucks.

Now there is a lighter alternative: shutdown SMTP for those who are not your users.

Here's the trivial code, implemented as a SPP plugin, fit to be used in the [mail] section:

#!/bin/dash

if [ -f /var/qmail/control/overloaded ]
then
      if [ -z "$SMTPAUTHUSER" ]
      then
              echo R451 Temporary Failure: Server overload
              echo overload: $PPID Temporary Failure: Server overload >&2
      fi
fi

And if you are daring and want to make your system self-correcting, maybe you should cron something like this:

* * * * * if [ `qmail-qstat  | tail -1 | cut -d: -f2` -gt 100 ];\
then touch /var/qmail/control/overloaded ;\
else rm -f /var/qmail/control/overloaded; fi

I will probably code it again in C and make it part of ra/plugins.

2008-02-25 18:31

Weird Django/PyODB bug

I am finishing my first large-ish Django app from scratch [1].

To login a user you can do something like this:

[root@wally app]# python manage.py shell
Python 2.3.4 (#1, May  2 2007, 19:26:00)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from pyodb import *
>>> import django.contrib.auth
>>> print django.contrib.auth.authenticate(username='user',password='pass')
user

And then you use that user object for django.contrib.auth.login

Some of the authentication data is available on a Microsoft SQL Server, and I get it via pyodb. And this happens when I try to authenticate the user (assume user and pass are valid, this is the smallest snippet that triggers the bug):

[root@wally app]# python manage.py shell
Python 2.3.4 (#1, May  2 2007, 19:26:00)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from pyodb import Connect
>>> import django.contrib.auth
>>> c1=Connect("sqlserver",uid="user",pwd="pass")
>>> print django.contrib.auth.authenticate(username='user',password='pass')
None

As you can see, the pyodb stuff should not interfere with the django stuff at all. I am only importing one function and connecting to the DB, I don't even execute any SQL or use any data from the SQL connection. But the calls to authenticate fail.

How are you supposed to debug this? I worked around it by moving the PyODB stuff to another module, but it's weird.

[1] It's a list server. Discussion groups, moderation features, subscriptions, the works. Like google groups, but yours and not ajaxy. It's not Open Source software, but if you want something similar, I am sure my customer will license it to you :-D

Contents © 2000-2018 Roberto Alsina