SPF Record

Gmail has started bouncing my order confirmation emails so I need to start using some of the anti-spam indicators. One of them is an SPF record. Since I use Linode, there is a tab that lets me create the record. Deciding what to put in it is a bit complicated, but not too bad.

You can create a very simple SPF record or more detailed. I chose to get a little detailed in hopes that it would satisfy Google. You can find details of all the parameters at OpenSPF or Wikipedia.

The simplest record just says to allow all mail from the domain if there is a mail record in the DNS.


example.com  text = "v=spf1 mx ~all"

To see what an SPF record looks like, open the terminal and type the following


nslookup -type=txt Google.com

Your response should look like this:


google.com  text = "v=spf1 include:_spf.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all"

If you are using a Linode VPS, mail is sent using IPV6 so you also need an ip6 record. Linode itself uses MailChimp, so their SPF record is:


linode.com  text = "v=spf1 mx include:servers.mcsv.net ~all"

In my case, I set up my SPF record to include charter.net, since I also mail from the office and both my IPV4 and IPV6 address. In the Linode control panel, the data between the quotes is pasted into the form and Linode takes care of creating the record.

Removing items from NSMutableArray’s

I have an NSMutableArray in Objective-C that I want to remove items from so that it has just the number of items that will be displayed in a grid on the screen. The number of items varies, but on one screen it is 9. The array has more items, but I don’t necessarily know how many. [Remember that array items are numbered with an index starting at 0. So the last index number of my array of 9 items is 8′]

This is the original code that I tried.


NSUInteger itemsOnScreen = 9;
for (NSUInteger i = itemsOnScreen; i < gridItems.count; i++) {
    [gridItems removeObjectAtIndex:i];
}

This code doesn’t delete all of the items so I decided to start at the end and delete items until I there were only 9 left. This is the code that I ended up using.


NSUInteger itemsOnScreen = 9;

for (NSUInteger i = gridItems.count - 1; i > itemsOnScreen - 1; i--) {
    [gridItems removeObjectAtIndex:i];
}

It’s kind of ugly and after working with it it occurred to me why the original code didn’t work. As I started deleting items, the number of items, and hence the index of the last item changed. So it worked fine for the first few, but as I neared the end of the loop, there were no items with an index that matched i. If I just delete the first item after the 9 that I want, then the loop works fine.


NSUInteger itemsOnScreen = 9;
for (NSUInteger i = 0; i < gridItems.count; i++) {
    [gridItems removeObjectAtIndex:itemsOnScreen];
}

all mail servers must have a PTR record with a valid Reverse DNS entry

After we moved from our own server to Linode I started getting these bounce messages from Comcast. Reverse DNS just means that if you have an IP address you can find the domain associated with it. In my case I have lots of domains at the same IP address but use one for sending mail. I didn’t know what a PTR record is so I looked it up. Wikipedia says that “IPv4 uses the in-addr.arpa domain and the ip6.arpa domain is delegated for IPv6. The process of reverse resolving an IP address uses the pointer DNS record type (PTR record).”

On our old server we did our own DNS hosting and all of the info was contained in a file. So I knew about MX records, A records, etc. Linode uses a control panel to do the DNS setup so the setup is a bit different, but the same info is there. I had an A record for the domain that was sending the email, mail.machinename.com, and one for the domain that the email was coming from i.e. support@mycompany.com.

I checked with intoDNS to make sure that everything was set up correctly and I did in fact have a PTR record that pointed to the right place. “Your reverse (PTR) record: 192.168.255.173.in-addr.arpa -> mycompany.com”.

The clue came in a bounce from a different domain. The message said that the reverse DNS for 2500:34e80::f03c:92ee:fg70:ab93 was not found. It turns out that this is an IPv6 address. It appears that Linode is using an IPv6 address for the port I send mail from. To get a reverse DNS set up for that address I needed to set up an AAAA record in the Linode control panel, wait a while for it to propagate to Linode’s DNS servers, then set up reverse DNS for the IPv6 address.

I waited a day for the change to propagate and now my Comcast emails are going through fine.

UIImage Crash on iPod Touch

While testing my app on an iPod Touch I started getting an out of memory crash. It turns out that when using imageNamed: iOS keeps the picture around in case it is needed later. It is supposed to remove it from memory when it needs more memory, but it is slow to do so and causes the app to crash. I replaced it with imageWithContentsOfFile: and the crashes went away.

VM Tracker.png


/ Put the picture on the screen. Most will be jpegs
    //NSString *pictFileName = [NSString stringWithFormat:@"%@.jpg",pictName];
    NSString *pictFile = [[NSBundle mainBundle] pathForResource:pictName ofType:@"jpg"];
    if (  [PICT_TYPE isEqualToString:@"png"] ) {
        //pictFileName = [NSString stringWithFormat:@"%@.png",pictName];
        pictFile = [[NSBundle mainBundle] pathForResource:pictName ofType:@"png"];
    }
    
    //self.imageToDisplay  = [UIImage imageNamed:pictFileName];
    self.imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
    

From the documentation for imageNamed:,

This method looks in the system caches for an image object with the specified name and returns that object if it exists…
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.

So for all of my icons that remain on the screen, e.g. microphone, speaker, checkboxes, I use imageNamed:. They are small and reused so they belong in the cache. For the main image on the screen, which is large, there will most likely be lots of other images used before it is used again. The cache will be purged before the app gets around to using it again so there is no point to putting it there in the first place.

Non-Hackers as Founders

This is a continuation of my thoughts about founders that I started in the post on Women as Founders. There are literally thousands of startups out there, most of which you’ve never heard of—either because the solve a problem that you don’t have or because they never got the number of users required to be a sustainable business. I started at the beginning (2005) and looked through the list of startups funded by Y-Combinator. Looking through the list from the first few years, most of the startups solved problems that other hackers had. Part of this is no doubt due to the fact the Y-Combinator was founded by successful hackers. But part of it was not doubt due to the fact that the founders were solving a problem that they had. Most of the startups seem to be other solving technical problems, website design, secure payments, photo editing. Or they solve a communication problem, or social connection problem.

I’ve started several web-based companies. The ones that failed to get up and running did so because I was relying on other people to do the actual development. In 2001 my cousin was getting married and I thought it would be good to put up a website where people could share photos of the bride and groom, exchange anecdotes, and coordinate travel plans. There was even an obvious revenue model—link to hotels and gift-registeries and receive a commission on purchases. We could expand the site to other special events like reunions, golf-events, fund-raising walks, etc. The opportunities seemed wide open.

While I knew a little about programming a website, I didn’t know enough to do the whole thing. So I enlisted a partner to do the coding. The thing about coding is that even if you have a detailed specification, which we didn’t have, there are lots of decisions that get made on a regular basis that affect the final product. And every decision that the coder made was different from my vision. A lot of the things were things that just never occurred to the programmer. For example, if you have several pages on the site that start with a photo, they need to be in exactly the same place on every page. Otherwise when you move from page to page, the pages jump all over the place. And back then, most people were still using small monitors, so we couldn’t design a page that was wider than around 600 pixels or else people would have to scroll sideways to see it. Likewise, we needed to stick with a 65,536 color palette for most of the design. At the end I literally spent more time trying to persuade the coder to do things the way I wanted than they spent coding. I would have been better off spending the time learning how to code myself and then coding things the way they were supposed to be coded.

And I think that’s the difference between a coder and a hacker. The coder just wants to get the project done. The hacker wants to get it done right.

Since then, I have never let someone else be the coder on my projects. I will pay people to help me out when I am first learning a new language, but I do my own coding. And none of my projects have failed because they didn’t get built.

That’s not to say it couldn’t work. I can see how having a non-coding founder would be great for lots of startups, especially those that rely on face-to-face marketing or lots of back-end coordination with other businesses. But the kinds of startups that require a lot of coding seem to me to require hackers as founders.