Archive for Uncategorized

Outlook VBA macro to post email body to the web

At the request of one of my managers, I looked into the possibility of using Outlook to automatically post the contents of an incoming email to a website (an internal group wiki in this case). We previously used procmail to accomplish this task, but now that all email has migrated to Outlook/Exchange, that’s no longer an option. It turns out this is pretty easy to accomplish using the VisualBasic for Applications (VBA) macro capabilities built-in to Outlook.

The basic pieces to make this work:

  1. A Rule in Outlook that matches the specific email criteria, and runs a script (Outlook Macro)
  2. The Outlook macro which pulls out the message body and posts to a web site
  3. The web site / CGI to handle the incoming message

Setup the Outlook Rule

The first part is the easiest – define a rule with filters to match specific messages that should be forwarded onto the web site. The filter criteria should be as specific as possible — not generally a good idea to be posting arbitrary email messages onto a website. The action should be “run a script”. The ’script’ has to be a macro with a specific signature, like this:

Sub PublishMsgToWeb(Msg As Outlook.MailItem)

That defines a macro specifically intended to handle Outlook message (Outlook.MailItem instances).

Define the macro to post to the web

The macro is pretty simple: ready the message body and any other data of interest from the Outlook.MailItem object, package the data up into an HTTP POST request, and send it off.

Sub PublishMsgToWeb(Msg As Outlook.MailItem)
    Dim URL As String
    URL = "http://example.com/post-msg-from-outlook.cgi"

    Dim Subj As String, Body As String
    Subj = Msg.Subject
    Body = Msg.HTMLBody

    PublishMsgToURL URL, Subj, Body
End Sub

Sub PublishMsgToURL(ByVal URL As String, Subject As String, Body As String)
    Set xhr = CreateObject("MSXML2.XMLHTTP")
    xhr.Open "POST", URL, False
    xhr.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"

    data = "subj=" & URLEncode(Subject) & "&" & "body=" & URLEncode(Body)
    xhr.Send data
End Sub

I split the macro into two different pieces for testability. The HTTP POST request is done by instantiating an MSXML2.XMLHTTP request. Web services in Outlook seems to be a bit of a muddy subject, with multiple flavors of XmlHttpRequest. MSXML2.XMLHTTP is what I found to work in my version of Outlook 2003. YMMV.

The only real trick to putting the request together is in encoding the data as “application/x-www-form-urlencoded”, the format typically used for POST requests. I used the URLEncode() VBA function to encoded each piece, then joined them together into a normal query string

subject=…&body=…&…

This example just sends the message subject and body. Obviously there has to be an agreeement between the macro and the receiving website as to what data the request body should contain. Date, sender, and others are readily accessible from the Outlook.MailItem.

Define the CGI on the website to receive the message

For the purpose of this example, I just put together a simple CGI script in Ruby:

#!/usr/env/bin ruby
require 'cgi'
cgi = CGI.new

subj = cgi['subj']
body = cgi['body']

File.open("msg.html",'w') do |fh|
fh << <<END
<html>
<head>
<title>Outlook msg: #{subj}</title>
</head>
<body>
<h1>#{subj}</h1>
#{body}
</body>
</html>
END
end

print cgi.header( "type" => 'text/plain' )
print "ok\n"

This just saves the message content to a static html file that can then be viewed in a browser. The script just returns a simple ‘ok’ message back to the caller, but that will not actually be seen by anyone since the Outlook macro handles this transaction behind the scene.

So there’s the basic framework for posting email to the web using the built-in Outlook rules and macro capabilities. Whether or not this is actually a good idea is another question altogether…

Comments (3)

Boulder/Denver New-Tech Meetup Feb 2009

The Bounder/Denver New-Tech Meetup for february was excellent, glad I was able to attend.  New this month was a live twitter feed for the all things #bdnt.  Evidently the 350-ish people there (only a few of whom were actually tweeting) managed to push #bdnt into the top 5 trending tags (which reminds me, this twitter tag trend of the superbowl is very cool).  The beer thread was especially entertaining.

This is the 4th BDNT meetup I’ve attended, and mostly they seem to be about startup companies at various stages giving a 5-min spiel about what they’re doing, business model, next steps, etc — so lots of ‘new’, but doesn’t seem to be so much ‘tech’ in the mix.  I’d like to see people just showing off cool technology they’re messing around with.

In that vein, I talked to Robert Reich (BDNT founder) afterward to get his take on the philosophy of the group and such.  It sounds like that kind of pure-tech presentation is welcome, but it does have to pass his bar of interesting for the group.  I did throw out the possibility of talking about what I’m doing with microblogging inside intel, and it could work.  There’s quite a bit to do before I would have enough to show there, but it would be interesting (for me, anyway).  Not that I love to speak publicly, but it would be a great chance to make some connections.

Comments (1)

twitter for the enterprise?

Interesting last two days inside Intel, at least for me.  There was a bit of a stir about employees using yammer — concern about potential for sharing sensitive data on an externally-hosted service.

I haven’t been using twitter for very long, but I had wondered about the availability of a twitter-like service for internal use.  Intel is a big company, lots of opportunity for sharing and following what else is happening.  Somehow I missed the memo about the group on yammer.

Anyhow, through the course of it all, I was exposed to yammer (along with everyone else in the company…) When I joined the group, the discussion was all about possible alternatives that could be hosted internally and thus be approved for some of the conversations people would like to have.

laconi.ca was proposed as a possible platform, so I looked into it.  I happened to have a web server allocated to me that could host a deployment for evaulation.  Setup was reasonably easy — if you ignore the hours spent trying to build php5 for the machine.  Probably didn’t help that I was falling asleep at the keyboard…

The laconi.ca app seems pretty full-featured, but there’s actually a fair amount that doesn’t apply to this type of deployment — we won’t be using OpenID logins, SMS is probably not useful, won’t be supporting cross-posting to twitter, etc.  All of those things have to be hacked out of the code, unfortunately, as it is not very modular / configurable codebase.

One thing I’d really like to change for this purpose is to increased the limit for messages from 140 to 250 characters or so.  Since it most likely won’t end up supporting SMS, there’s not much point in restricting to 140 characters.  Encouraging brevity is a good thing, but 140 is a bit too short.  But once again, there’s no simple way to configure that.  The 140 limit is built into the database scheme, into the middleware, and also hard-coded in the client javascript code.  A bit disappointed by that…

I worked with one of the active yammerers to do some initial testing, then announced it to the rest of the yammer group.  That all happened on Friday afternoon, so there hasn’t been a lot of response yet, but it seems mostly positive so far.  Yammer definitely has some nice functionality that will be missed (e.g. threaded conversations and groups), but this has the huge advantage of being entirely contained within the copany network.

At the same time I was doing this, I found out that the corporate IT group is working on a full-blown “professional social network” solution for everyone, which will include an integrated micro-blogging function.  That will roll out starting in about two more months…. Being part of a large effort, I don’t expect much from that micro-blogging feature.  Frankly I expect it to suck.  Doing it right is hard enough in relative isolation (twitter/yammer/laconi.ca are not trivial), so doing it as a small part of a larger system will result in a ho-hum, watered-down service that will struggle to engage many users.

Hopefully the laconi.ca-based service will get some traction in the meantime.  If there’s enough momentum, it can’t be ignored.  That’s how previous grass-roots efforts with blogging, wikis, etc have evolved within Intel.  The yammer situation has demonstrated a pretty clear demand for this capability.  Not sure how my involvement in the whole thing will play out, but I hope it remains interesting.

Comments (1)

Overnight success takes years

Great advice in a post on Coding Horror, from Jeff Atwood and others.  This title made me laugh: Teach Yourself Programming in Ten Years.  I started playing around with BASIC on the Apple II’s at school in 4th grade, then on my parents’ Kaypro II.  So I’ve been been at it a long time.  There’s a whole lot left to learn.

I also (sort of) studied violin for ~15 years.  I can manage to play a few things well, but it’s mostly frustrating, because I can’t just pick it up and play.  And I know what it would take: consistent, dedicated practice — not just playing, but practice, doing specific exercises to develop specific skills and expand my repertoire.

The same definitely applies to software and business development.  I’ve had extensive experience with some technologies in some application domains, but there’s so much I don’t know.  I’ve definitely reached a stage in my professional career where I’m starting to feel like things should be happening, and it is hard to be patient and keep slogging away.  Keep learning something new — that’s the easy part, actually.  Focused, intentional practice is not so much fun.  But I’m in it for the long haul, maybe one day I also will be able to wake up an overnight success.

Comments

Implementing a ‘ruler’ with Raphael and jQuery

Investigating a click-and-drag ruler to measure dimensions on-screen.

I used jQuery for event handling and such, and Raphael for drawing the lines. Since it’s just two straight lines, I probably could have done it just as easily with html elements (e.g. setting two borders on a positioned div…) That would probably end up being more robust concerning cross-browser compatibility. Oh well. See the demo here.

There’s nothing innovative here, just something I need to implement for a project. It turns out to be a bit involved to handle all parts of the interaction. The basic idea is:

  • on mousedown: register the starting point, and create the lines and labels (Ruler.start())
  • on mousemove: update the end point and redraw the lines and labels (Ruler.move())
  • on mouseup: hide the lines and labels (Ruler.finish())
var Ruler = function (elem) {
  elem = $(elem);
  this.elem = elem[0];
  this.raph = new Raphael(elem[0],elem.width(),elem.height());

  var b = this;
  elem.mousedown(function(e) { b.start(e); });
  elem.mouseup(function(e) { b.finish(e); });
  elem.mousemove(function(e) { b.move(e); });
};

The full implementation came to about 125 lines, tested in Firefox 3, and IE 7. I’ll cover some of the tricky issues here.

Bias

The ruler feels more natural if it follows the direction the mouse is moved—if I drag the mouse left or right, then it draws the horizontal segment first, followed by the vertical; if I drag the mouse up or down initially, it draws vertical then horizontal.

The code waits for at least a 10-pixel movement from the starting point to determine the user intent, and then fixes that as the bias for the ruler. This affects the ordering of the line segments, as well as the placement of the text labels.

  bias: function(left,top) {
    var dx = Math.abs(this.dx);
    var dy = Math.abs(this.dy)
    if ( (dx+dy) > 10 )
      this.dir = (dx > dy) ? 'h':'v';
  },

The lines

The two line segments are drawn as a single Raphael path element. Instead of re-creating the path for each movement, it updates the points in the path instead. Raphael makes this easy:

  draw_lines: function(left,top) {
    var p = this.path.path;
    if ( this.dir == 'h' )
      p[1].arg = [left, this.start_at.top];
    else
      p[1].arg = [this.start_at.left, top];
    p[2].arg = [left, top];
    this.path.redraw();
  },

The text labels

The labels showing the horizontal and vertical distance are drawn with two dynamically-created divs, positioned absolutely. I want these to be treated as passive annotations on the page, but since they are actual DOM elements, they are treated just like any other text on the page—the get selected when the mouse goes over them while the mouse button is down (i.e. while dragging the ruler).

So, when the ruler drag is started and it is short, the mouse is over the text labels, and the browser selects the text as it is supposed to. Not a nice effect. I found this solution for making the text non-selectable in a cross-browser manner, but with limited success.

  draw_labels: function(left,top) {
    var hl, ht, vl, vt;
    if ( this.dir == 'h' ) {
      // horz label
      hl = (this.start_at.left + left)/2;
      ht = this.start_at.top;
      // vert label
      vl = left + 2;
      vt = (this.start_at.top + top)/2;
    } else {
      // horz label
      hl = (this.start_at.left + left)/2;
      ht = top;
      // vert label
      vl = this.start_at.left + 2;
      vt = (this.start_at.top + top)/2;
    }
    $(this.hlabel).text(this.dx).
      css({left: (this.offset.left + hl)+"px",
           top: (this.offset.top + ht)+"px"});
    $(this.vlabel).text(this.dy).
      css({left: (this.offset.left + vl)+"px",
           top: (this.offset.top + vt)+"px"});
  },

mouseup outside of the div

If the mouse leaves the #paper div, and then the user releases the mouse, the Ruler.finish() method never gets called. This has a very simple solution: in Ruler.start(), don’t do anything if the ruler is already in progress (the previous mousedown), so the user just has to click again inside the div to finish it.

Am I making this too hard? Feel free to point me to easier/cleaner/better solutions…

Comments (1)

Pedigree navigation mockup

Now that I have a gedcom parser to work with, I loaded up a mockup pedigree view I’ve been working on with some real data

pedigree mockup

Next steps:

  • navigation to children, siblings
  • draw connecting lines
  • popup for details on a person

At some point I’ll abandon this code to start working on the ‘real’ implementation, but it’s a good vehicle for prototyping for now. All done in Javascript (~560 lines), with a bit of help from the dojo toolkit.

Comments

Ruby GEDCOM::Parser module

Getting ready to do some work on yology, I needed a good way to get at some sample date. Numerous GEDCOM files are readily available, but I only need a subset of the data for the mockups I’m planning.

I took a look at the existing ruby GEDCOM::Parser, but wasn’t satisfied. So I forked it and hacked away. See the full writeup for details.

Comments

Tk-GraphViz 1.01

I just upload Tk-GraphViz 1.01 to CPAN. Alternately, download it here

This is a very minor update with some additional polygonal node shapes. This module could use some serious updating to get in sync with the latest graphviz—the first version went on CPAN back in 2003.

Comments

Follow me on twitter

http://twitter.com/jslade

I plan to use that twitter profile for tech-related stuff

Comments

git socks proxy with ssh2

Rufus Cable at ThreeBytesFull posted a helpful writeup on using a SOCKS proxy for git access from behind a corporate firewall.

In my corporate environment, we don’t use OpenSSH, but rather Reflection for Secure IT, which is ssh2. The only change I had to make from his instructions was in the socks-ssh wrapper script—using the SocksServer config option instead of ProxyCommand:


#!/bin/sh
# Filename: ~/bin/socks-ssh
# This script opens an SSH connection through a SOCKS server
ssh -o 'SocksServer http://myproxy.mycompany.com/' $@

Comments