Aiming for elegance, one thought at a time

The path to productive effort: waste

Posted: September 13th, 2013 | Author: | Filed under: Uncategorized | No Comments »

This silhouette is no fake

A few weeks ago I wrote about taking pleasure from putting effort into marketing. As I was writing that post, I had a moment of realisation. I’d been tossing these ideas around in my head, but committing them to paper made the much more concrete. So, has that moment of realisation led directly to a change in behaviour?

Well. Not quite yet.

I spoke about my rock climbing and how enjoying the effort has helped me get to the next level. What’s easy to forget, though, is the seven years of practice I’ve already put in. My mind and body already know the basics. I’ve got some idea of what productive effort should feel like.

When it comes to marketing, I don’t even know what productive effort feels like. So much of it feels like spinning my wheels and getting nowhere. I can really relate to Andrey Butov’s comments on the bootstrapped podcast. You put in all is effort today that might not pay off for months – or might not pay off at all. It’s all well and good to enjoy the effort, but you don’t want to be wasting time.

The best way to minimise wasted effort is to surround yourself with others who have already done it. The only way to avoid wasting effort altogether, though, is not to try. And that’s not a real option. The path to productive effort is by putting in the hard graft, and accepting the failures with the successes.


Technical founders should add marketing to their development sprint

Posted: September 6th, 2013 | Author: | Filed under: Uncategorized | No Comments »

Sprinting Dassie

As a technical founder, I’ve been finding it difficult to balance the stuff I enjoy (development) with the stuff I find hard (marketing.) This past week, I’ve started adding my marketing tasks to my development sprints, with about a 2-1 ratio. In terms of what I’ve actually executed so far in the sprint, it’s been 80% dev and 20% marketing. But at least I know that now, and can aim to beat it next time!


Smile first, then market – every day

Posted: August 31st, 2013 | Author: | Filed under: Uncategorized | No Comments »

Smiles...

I’ve spent the better part of a month building my launch list now, and have got just four people signed up.

All is not going to plan.

Now, there’s a certain temptation do get disheartened. I’m resisting that. It’s better to stay focussed on the effort, rather then worrying about hitting or missing the goal. (And, it’s better to aim high and miss then to aim low and get there. That said, my ‘low’ – unpublished – aim was around 50 signups, and on current trends I’ll miss that too.)

Staying focussed on the effort

I rock climb. I’ve been climbing for about 7 years now, with a couple of breaks. For the longest time, progress was slow; my attention was caught up in what I wanted to do, and not what I was doing. The breakthrough came this year when I read The Rock Warrior’s Way by Arno Ilger. Arno writes that our attention needs to be focussed on what we’re doing, and that we need to derive our satisfaction from the effort we put in, and not the result.

Deriving satisfaction from results is dangerous, because we’re never fully responsible for the result. A good result isn’t entirely due to our efforts, and neither is a bad result. If the economy collapses, then you can’t shoulder the entire responsibility for your bootstrap taking of slowly. On the other hand, if the economy is booming, then success isn’t entirely yours either.

Instead, derive satisfaction from the effort, because that really is wholly yours. Having done that for a few months, I’m climbing stronger than ever.

Enjoying the effort

I also read Born to Run a year or so ago. Great book. One section that I remember particularly talks about how the very best long distance runners – we’re talking 150 miles or so – just love running. They smile, and laugh, and run. If you don’t enjoy it, you won’t clock up 150 miles, will you?

Bootstrapping is the mother of all ultra-marathons.

Oversimplified? Perhaps. Even if we are born to run, no one’s going to be grinning when the first get off the couch and plod around the block. Likewise, working out how to market isn’t going to be a joyful experience right off the bat. On the other hand, smiling makes you happy, so maybe I’ve got the causality all wrong here….

Smile first, then market – every day

When it comes to marketing, I’m that guy just getting up off the couch for the first plod around the block. And so far, it would be fair to say that I’ve been more worried about whether I’ve got the right sneakers or not. So, sure, it feels weird and I’m not really sure what I’m doing exactly, but I figure that if I smile first, then market – every day – I might just get to love it.

ps… if you’ve got a web app that sends email, check out Trace Email Studio.


Lesson learnt: have a plan!

Posted: August 20th, 2013 | Author: | Filed under: Uncategorized | No Comments »

In the past 10 days, I’ve doubled my list: from 1 person to 2. Hmm, this is really not going to cut it.

Now, to be honest, I have not been executing effectively on a plan. Part of the problem, there, is that I don’t really have a plan to execute effectively on. So for anyone out there reading this: have a plan.

Ideally, that plan should be grounded in reality and have concrete steps that will predictably lead to reaching your goals. In my case, the goal is a list of 500 potential users. One of my original ideas was to approach people and ask them to have a look. That met with some (very) small success in terms of signups, but perhaps more importantly, gave me some really great feedback on what’s wrong with the site. The problem with this approach is that it doesn’t scale, but that’s OK because I’ve got some feedback that otherwise I wouldn’t have got:

  • Why reinvent the wheel? Just knock off other people’s successful landing sites. Perhaps grab something from unbounce?
  • Too much text! Cut it down much more!
  • Focus on benefits – why the heck do I want this?
  • Uhhh… what is this anyway?

So it’s clear that I need to improve the landing site. But even once that’s done, I need to work out how to drive some traffic to the site – and there I’m still short of a plan.

(As an aside, this really made me think of The Fallacy of Lessons Learned. None of this is particularly new, or groundbreaking; they we’re all things I’ve heard before. There is quite a leap between ‘knowing’ and ‘doing’, though.)


10 days of building an audience… 1 subscriber

Posted: August 7th, 2013 | Author: | Filed under: Uncategorized | 2 Comments »

Well, 10 days in (or so) to my 60 day effort to build a pre-launch list of 500 email addresses for Trace Email Studio, I’ve managed to get one person signed up. Hmm, a little bit disappointing, I must say. However, I’ve got to say – this really is to be expected. I’m starting from a low base, and I’ve got a lot to learn. So. What have I learnt?

Traffic numbers

The total hits to the site have been around 42, or thereabouts. The main two sources have been discussed.bootstrapped.fm – people clicking through from the link in my profile – and ‘direct’. ‘Direct’ is going to be a combination of a) me visiting the site on different devices and b) sending the link to a bunch of people I know who I thought might be interested, and asking for feedback.

So out of approaching 10-15 people I thought might be interested, did I have a conversion rate of 7.5%? No, in fact, I believe my one signup saw my profile on LinkedIn, googled me, and found Trace Email Studio that way. My direct approaches to people have so far resulted in no signups to the list. To be fair, I’m asking for feedback rather than asking them to signup, so it’s not exactly like I’m going for a hard sell.

But I did get some useful feedback!

The feedback that surprised me most, is that this comes across as a tool aimed at developers. This surprised me because I’ve developed it with non-developers in mind. I’ve been labelling my customer as ‘marketers'; I’m not sure how precise that label is. Firstly, there’s a lot of things that marketers do that Trace Email Studio doesn’t really address – even if you narrow it down just to email marketers. Trace Email Studio is really looking at transactional emails first and foremost. This is a small part of email marketing, and perhaps not where most email marketers would spend most of their time.

Moreover, transactional emails are not necessarily first-and-foremost the domain of marketers. Support, operations, and development are all likely more directly impacted by the transactional email, even if, yes, transactional emails can be deployed very effectively as a marketing tool.

The other part of this is that, as much as I’m developing this with non-developers in mind, I am in fact a developer. Perhaps my voice is just naturally more “developer” than anything else. If that’s true, then perhaps it’ll be fair easier and more authentic to pitch straight at developers.

Next up

I do want to run this by some more marketing types, to confirm if there is any interest here. Beyond that, I need to tart up the landing page and create a landing page aimed at developers.

 


Can I build an audience through direct sales?

Posted: July 31st, 2013 | Author: | Filed under: Uncategorized | 4 Comments »

If I’m going to build an pre-launch list of 500 potential customers in just 60 days for Trace Email Studio, I’m going to have to get cracking.

At the end of day 1: big fat zero.

Thought I’d give direct sales a go. Reaching out to people I know. I emailed 10 people. I guess I don’t know that many people in my target market. And then I came across some interesting interviews with two of the founders of pipedrive, Urmas Purde and Timo Reid (the Mixergy interview with Timo is especially awesome.) While they’ve moved away from direct sales, their first 50 or so beta users were from direct sales. How many contacts did they get in touch with to find 50 beta users? 500. 500 contacts! Wow. 10% conversion rate, and that’s when these were people they’d worked with in the past.

I’m really gonna have to lift my game. Either, I need to covert at 90% (ha!) or I need to send 100 emails a day. Today, to send 10 emails took me 6 hours. So, all I need to do is work 60 hours days, and I should be able to make it just fine.

Hrm. I might need some other strategies…


Startup challenge: build an email list of 500 prospects from nothing in 60 days

Posted: July 30th, 2013 | Author: | Filed under: Uncategorized | 1 Comment »

I’m coming pretty green to this whole startup game. I’d already quit my job before I even picked up The Lean Startup! The learning curve is pretty steep.

“I’ll build a great product, and then customers will appear! It’ll be so great, it’ll grow by word of mouth!” – me, embarrassingly recently.

Shockingly naive, right? (The product is great though. Trace Email Studio will help you send personalised lifecycle emails and move the needle on your startup. In a nutshell: Trace Email Studio will help you send the right email to the right person at the right time, and it’ll help you do this faster. Because you can do it faster, you’ll be able to do it more. Because you can do it more, you’ll make more money. QED.)

I recently had a revelation: I need to market this thing. Common knowledge for some, and I’ve probably been told about a million times. It took a while to sink in. What finally made it click was reading recently (can’t find the link, but I think it was Rob Walling) startups should have at least 500 names on your pre-launch email list.

So I’m setting myself the goal of building an email list of 500 prospects from absolutely nothing in 60 days.

What does “nothing” mean, in this case?

  • I’ve only just put the pre-launch page up.
  • I’ve got 12 twitter followers. (High school friends.)
  • I’ve got this blog with… erm, no real focus, sporadic posts, and consequently no readers.
  • And, shockingly, I don’t have any VC buddies.

And some rules:

  • I’ll only count people in the target market and at least theoretically able to benefit from lifecycle emails (so they need to have enough customers).
  • I’ll only count people who can (at least) influence a purchasing decision.
  • I’ve got to have at least 100 people on the list who could actually authorise a purchase

So I’ve got my work cut out for me. I’m going to post this on Hacker News in the hope that someone will take mercy on me and give me some great advice.


News can’t make money on the internet, 2013

Posted: July 27th, 2013 | Author: | Filed under: Uncategorized | No Comments »

Dave Winer’s got an interesting article about how news can make money on the internet:

The answers are so obvious there’s no need to explain.

You should definitely read the original. I’ve cut out a bit. The last part really caught my eye, though. The answer is not obvious at all.

When I think about what I want from a news organisation, I want level-headed coverage of current affairs, in depth research, and unbiased analysis. In effect, I want information I can trust to help me become an informed citizen. Not an entertained consumer. An informed citizen.

Did that kind of organisation ever exist? Perhaps not. Was it closer than today? Probably. What’s changed to move us farther from that ideal? I certainly can’t say – it’s more than just the internet. I’d bet that there’s some underlying social changes there that a news organisation in 2013 ignores at their peril.

Now you can disagree with me about many points here. Have I misinterpreted Dave? Is my ideal news organisation out of kilter with what most people want, or some platonic ideal? Does it already exist? If it does – it’s not making money.

You might disagree with a lot. You have to agree with one thing though.

The answers aren’t obvious.


Adding “verify” URLs to an express.js app to confirm user emails (Secure SPA Part 6)

Posted: May 17th, 2013 | Author: | Filed under: Uncategorized | 3 Comments »

This is the sixth part of a series of blog posts that will walk step-by-step through the process of creating a secure Single Page App (SPA) using node.js, passport.js, and Angular. In Part 5, we sent an email to confirm the users email address. In this instalment, we’ll be wiring up the backend to actually provide a working verification URL.

The verification token

The url we’ll be using will take the form:

http://www.yourhost.com/verify/token-uuid

The bit we’ll be most interested is the token-uuid, which we’ll be using node-uuid to generate. We’ll use a type-4 (random) UUID and we’ll make sure that these tokens expire in a given amount of time. Combine cryptographically strong random UUIDs with a short expiry date and the chance of collisions is practically nil. That said, if you’re worried about collisions, you could either change this code to protect against it, switch to Type 1 UUIDs (making sure each instance of node in your cluster has a unique node ID or swap to something like snowflake or noeqd. Seriously, though: the Type 4 uuid is random enough. Have faith in the maths.

Generating and storing the token

To make sure the tokens expire, we’ll be taking advantage of the TTL capability of mongodb. This is done simply enough: we add the “expires” index option to a “created_at” field when declaring the mongoose schema.

// Verification token model
var verificationTokenSchema = new Schema({
    _userId: {type: ObjectId, required: true, ref: 'User'},
    token: {type: String, required: true},
    createdAt: {type: Date, required: true, default: Date.now, expires: '4h'}
});

Our token is simply a random UUID, but here’s a convenience function to set the token and save the model, and then return the token in a callback.

var uuid = require('node-uuid');
verificationTokenSchema.methods.createVerificationToken = function (done) {
    var verificationToken = this;
    var token = uuid.v4();
    verificationToken.set('token', token);
    verificationToken.save( function (err) {
        if (err) return done(err);
        return done(null, token);
        console.log("Verification token", verificationToken);
    });
};

Create the and export the model:

var verificationTokenModel = mongoose.model('VerificationToken', verificationTokenSchema);
exports.verificationTokenModel = verificationTokenModel;

And finally, a convenience function to verify a user: it takes the token, locates the matching user, and sets “verified” to true.

exports.verifyUser = function(token, done) {
    verificationTokenModel.findOne({token: token}, function (err, doc){
        if (err) return done(err);
        userModel.findOne({_id: doc._userId}, function (err, user) {
            if (err) return done(err);
            user["verified"] = true;
            user.save(function(err) {
                done(err);
            })
        })
    })
}

Creating the token

In our user registration code, we can add the following. This wraps the ‘sendVerificationEmail’ function we created last time.

var verificationToken = new verificationTokenModel({_userId: user._id});
verificationToken.createVerificationToken(function (err, token) {
    if (err) return console.log("Couldn't create verification token", err);
    var message = {
        email: user.email,
        name: user.name,
        verifyURL: req.protocol + "://" + req.get('host') + "/verify/" + token};
    sendVerificationEmail(message, function (error, success) {
        if (error) {
            // not much point in attempting to send again, so we give up
            // will need to give the user a mechanism to resend verification
            console.error("Unable to send via postmark: " + error.message);
            return;
        }
        console.info("Sent to postmark for delivery")
    });
});

Verification middleware

The last remaining step is to create a simple middleware to check the token, and direct them to success and failure pages.

app.get("/verify/:token", function (req, res, next) {
    var token = req.params.token;
    verifyUser(token, function(err) {
        if (err) return res.redirect("verification-failure");
        res.redirect("verification-success");
    });
});

Wrapping up

You’re now sending verification emails and handling verification URLs: nice job! Stay tuned for more node.js, Angular, and SPA security next week!


Sending emails to confirm users’ email addresses using postmark (Secure SPA part 5)

Posted: May 14th, 2013 | Author: | Filed under: Uncategorized | No Comments »

This is the fifth part of a series of blog posts that will walk step-by-step through the process of creating a secure Single Page App (SPA) using node.js, passport.js, and Angular. Today, we’re going to send an email to confirm the users email address.

If you’re new here, you should start at Part 1, where we set up Passport.js.

The complete series of posts will cover:

  • Getting started with passport.js
  • Adding in users
  • Handling login, logout, and registration from a single page app
  • Adding in robust remember-me functionality
  • Protecting against CSRF
  • Protecting against XSS
  • Adding a reasonably robust remember-me to passport js
  • Enhancing security by adding some simple HTTP headers
  • Setting up to always redirect to SSL
  • Pushing our app to Heroku
  • Throttling login attempts

To do this, we’ll be using postmark and postmark.js. We’ll be sending an email with both text and html parts, which we’ll render using EJS, although you could use any old template engine. I like EJS for this case, as I’ve used an email template designed by mailchimp (aside: of course, you could just use mailchimp directly through mandrill!), and I didn’t relish the thought of converting it in to jade or something like that.

Prerequisites

You’ll need to sign up for postmark and then add a new server. Once you got that all set up, you should see something like this:

postmark-dashboard

Getting started

As of right now, I don’t have a full code example for this – I’ll update this post when I do. All in all, though, it should be pretty easy to retrofit this to your application. To add the dependencies, just run:

npm install postmark --save
npm install q --save

The code

Sending the email

To send the email, we’re going to need a few things:

  • The “From” address – this should match the signature you set up in postmark
  • The “To” address – the user we’re going to send this to
  • The “Subject” – self explanatory
  • The “TextBody” – the text of the email for email clients that don’t support HTML
  • The “HTMLBody” – pretty looking HTML that most recipients will see

Pro-tip: the main reason to include the text is to increase the likelihood of hitting the inbox.

To generate the textBody and the HTML body, we’re going to be hitting ejs.renderFile twice: once for text, and once for HTML. The templates are included below

var key = "YOUR POSTMARK KEY";
var postmark = require("postmark")(key);
var ejs = require("ejs");

function sendVerificationEmail(options, done) {
    var deliver = function (textBody, htmlBody) {
        postmark.send({
            "From": "daniel@dashi.ng",
            "To": options.email,
            "Subject": "Confirm your email address",
            "TextBody": textBody,
            "HtmlBody": htmlBody
        }, done);
    };
    ejs.renderFile("views/email-text.ejs", options, function (err, textBody) {
        if (err) return done(err);
        ejs.renderFile("views/email-html.ejs", options, function (err, htmlBody) {
            if (err) return done(err);
            deliver(textBody, htmlBody)
        });
    });
}

module.exports.sendVerificationEmail = sendVerificationEmail;

When you create a user

You’ll just need to trigger this function when you create a user. For instance:

var message = {
    email: user.email,
    name: user.name,
    verifyURL: req.protocol + "://" + req.get('host') + "/verify/" + token};
sendVerificationEmail(message, function (error, success) {
    if (error) {
        // not much point in attempting to send again, so we give up
        // will need to give the user a mechanism to resend verification
        console.error("Unable to send via postmark: " + error.message);
        return;
    }
    console.info("Sent to postmark for delivery")
});

The templates

To get you started, here’s and example HTML template (based on a WordPress template) and text template.

Next time

In the next installment, we’ll wire this up so that our validation URLs work the way we want.