Apr 17, 2013 - Development    Comments Off

PHP Email Bounce Script

A lot of people have asked for this. This is the email bounce script I use. You will have to pipe all emails to this file.

<?
//opens the stream
$fd = fopen("php://stdin", "r");

$content = "";

//read the lines
while (!feof($fd))
{
    $content .= fread($fd, 1024);
}
fclose($fd);

$lines = explode("\n", $content);

$email = "";

//SPAM report from feedback loop
for($i=0;$i<count($lines);$i++)
{
    if(preg_match("/^Original-Rcpt-To:(.*)/", $lines[$i], $matches))
    {
        $email = trim($matches[1]);
        $mode = "spam";
        $type = 2;
        continue;
    }
}

//bounced back message from receiving server
if($email == "")
{
    for($i=0;$i<count($lines);$i++)
    {
        if(preg_match("/^Delivered-To:(.*)/", $lines[$i], $matches))
        {
            $mode = "bounce";
            $type = 1;
            $email = substr(trim($matches[1]),2);
            continue;
        }
    }
}

//failed message, MTA emailed a failed message
if($email == "")
{
    for($i=0;$i<count($lines);$i++)
    {
        if(preg_match("/^Remote host said:(.*)/", $lines[$i], $matches))
        {
            for($j=0;$j<count($lines);$j++)
            {
                if(preg_match("/^Return-Path:(.*)/", $lines[$j], $matches))
                {
                    if(strstr($matches[1], "=") !== false)
                    {
                        $mode = "bounce";
                        $type = 1;
                        $email = trim($matches[1]);
                        continue 2;
                    }
                }
            }
            continue;
        }
     }
}

//return-path format is user=website.com@mydomain.com
//convert this into the actually email, user@website.com
if($mode == "bounce")
{
    $email = substr($email,0,strpos($email,"@"));
    $email = str_replace("=", "@", $email);
}

if($email != "")
{
    if(strchr($email, "@") !== false)
    {
        $domain = substr($email,strpos($email,"@")+1);
        $sql = "SELECT id
                FROM donotemail
                WHERE LOWER(email) = LOWER('".fix($email)."')";
        $result = query($sql);
        if($result)
        {
            if(numrows($result) == 0)
            {
                $sql = "INSERT INTO donotemail
                        (email, type, thedate)
                        VALUES('".fix($email)."', '$type', CURDATE())";
                query($sql);
            }
        }
    }
}
?>
Mar 12, 2013 - Development    Comments Off

PHP date_diff days negative zero issue

I ran into an odd problem today that I couldn’t find a solution to when searching Google. I ended up figuring it out and thought I should document it here for future searches.

PHP has a date_diff function from v5.3+. I was using this function to calculate the difference in DAYS between two dates. I found that the results I received did not match what I expected. PHP says the difference between Yesterday and Today is -1 (negative one) days. The difference between Today and Today is -0 (negative zero) days. The difference between Tomorrow and Today is 0 (zero) days. And the difference between Today and the Day After Tomorrow is 1 (one) day, etc. Say whaaaaat?

Duplicate this:

$day1 = new DateTime();
$day2 = new DateTime("yesterday");
$interval = $day1->diff($day2);
$interval = date_diff($day1, $day2);
$days = $interval->format('%r%a');
//%r = show negative sign or nothing
//%a = number of total days

echo "$days <br/>";

$day2 = new DateTime("today");
$interval = $day1->diff($day2);
$interval = date_diff($day1, $day2);
$days = $interval->format('%r%a');

echo "$days <br/>";

$day2 = new DateTime("tomorrow");
$interval = $day1->diff($day2);
$interval = date_diff($day1, $day2);
$days = $interval->format('%r%a');
echo "$days <br/>";

In order to get a difference value that I expected I had to write a statement to convert these values. I also ran into some odd comparison issues and had to resort to using === to compare the days. Even though I compared string to string I kept getting false positives. I threw together a quick conversion if/then/else that created the right type of “days” value for what I was expecting:

if($days === "-0")
{
//today
$days = 0;
}
elseif($days === "0")
{
//tomorrow
$days = 1;
}
elseif($days > 0)
{
$days = $days + 1;
}

PHP handled the other days in the past as expected, for whatever reason. The day before yesterday is -2 without any modifications.

Mar 1, 2013 - Development    Comments Off

Domain Name Availability / WHOIS API

On Naming Force we need the ability to check the availability of a suggested domain names. Previously we had used the eNom API to do this but received many complaints that the data was inaccurate. Also, we ran into an issues where eNom was blocking our API requests if we submitted “too many” in a short time period. They would flag our account for 30 minutes to an hour, during which we could perform no API calls. I contacted eNom support and they said there was no way to get around this and that they also would not tell us what the threshold was. Horrible idea for an API service, eNom. I searched for a replacement and came upon WhoisAPI. We have been using WhoisAPI for about a month now and it seems to be much better than the eNom API for checking availability of domains. The WhoisAPI is more expensive, but it’s tailored to exactly what we want to accomplish. I recommend WhoisAPI for anyone trying to find an API for checking availability of domain names.

Nov 7, 2012 - Business    Comments Off

Crowdsourced Website Marketing

The Problem

For about two years now I’ve had a vision for a way to crowdsource website startup marketing. You start an incredible new web service and you ask for the crowd to help launch it. Wahooly had the same vision but has a horrible implementation, IMO. There is a lot of “friction” around giving up equity in your businesses in order to “buy” traction from the public. I don’t think Wahooly will succeed (they’ve been in Beta for almost two years?) due to this business model. Before I ever heard about Wahooly, though, I started a crowdsourced marketing website, MemberMob. It ended up not taking off the way I had expected it to. Clients were emailing me asking when we would start taking orders but the crowd wasn’t signing up to be our workforce. After having outside consultants take a look at the site, a problem was identified. The crowd that we were targeting, the general public, wasn’t interested in pushing random websites to their friends via social media in order to earn a few bucks. We had not predicted this problem. We thought everyone loved money. Back to the drawing board.

The Solution

After taking some time away from MemberMob I came up with a “pivot” for the crowdsourced marketing concept. The idea of crowdsourcing website launches is so strong in me that I had to find a solution. The idea is simple. Entrepreneurs need a way to socially market their new websites without paying tens of thousands of dollars just to see if the service will be popular. But who are we going to find that is willing to help them out by posting these new sites to social media? Other entrepreneurs! Other entrepreneurs, who themselves want to market their own websites. It’s basically a cyber back-scratching. The new website is Lookafox!

How It Works

Entrepreneur A starts posting Lookafox! links to their social media account. Over a few months they earn hundreds of credits through their link clickthroughs. When the time is right, Entrepreneur A creates a social media campaign on Lookafox! Entrepreneur B has just registered on Lookafox! and wants to build equity to go towards his social media campaign. He sees Entrepreneur A’s social media campaign and posts a custom tracking URL to his Twitter account. He now starts earning credits for his own social media campaign while providing traffic to Entrepreneur A’s website. And on and on.

Conclusion

Through Lookafox! we can all get traction for our web startups without spending a fortune. You help me, I help you, we help him, and we all win. And get rich?

Oct 8, 2012 - Business    Comments Off

How to Choose a Business Name

Choosing a business name can be difficult. I speak with people all the time who are having trouble coming up with a name for their new venture. Here are a few ways you can come up with a business name.

Start a Naming Contest


You might not be creative enough to come up with a stellar business name, but thousands of people are waiting to help you. Naming Force hosts business name contests where the public helps name your business. Simply post a contest, and award, and they’re off and naming your new business. Naming Force ranks the name submissions so that you know which names are best.

Use a Random Name Generator

If you’re looking for a Web 2.0-style name a random name generator can be helpful. This Business Name Generator is perfect for generating modern name mash-ups.

Buy an Existing Brandable Domain Name


There are websites that specialize in selling existing, unused, domain names that are brandable names. Do you like Ardonia, Nymba, or Prosaria? They’re all for sale at ReadymadeNames.com.

Sep 20, 2012 - Business    Comments Off

How To Pass Your IRS Audit

Recently my single-member LLC was audited by the IRS. I met all the known triggers in the filling year in question, the most obvious being that I filed an amendment after noticing a major mistake in my initial filing (double-counted some income). Luckily I showed up to my audit prepared and was able to completely prove all of the items in question. According to my tax book the IRS normally wins 80% of their audits. And according to my auditor I was only the 3rd audit she had done in 2 years that passed. I couldn’t have done it without the tips below.

Tip #1 – Become Confident

This is absolutely the most important step. You must take the steps, prior to the audit, to become confident that a) you submitted your taxes properly and b) that you’re prepared to prove this. I can say that this was the single-most important factor to the audit going smoothly. I knew that I had filed my (amended) taxes properly and I knew that I had the proof. I had absolutely no doubt going in. Take the steps to be confident. This will mean following the steps below. Don’t overlook the importance of being confident in the validity of your filing. For me this step included reading the “Audits” section of the “Tax Savvy for Small Business” book I had laying around. This book was a lifesaver.

Tip #2 – Print Receipts

For my audit specific areas were being audited. These were the business expenses of “Advertising” and “Other expenses”. Lucky for me I use Quickbooks and also do my taxes 100% off of my QB data (tax report). This made it very easy to print off all of the transactions in question and start digging up receipts/invoices. Luckily most of the website services I pay on a monthly basis allowed me to sign in and print old (2010) invoices. Print every single invoice you can find for the tax year in question.

Tip #3 – Print Bank Statements

Sign in to your bank’s website and print every month’s statement for the tax year in question. Do not remove any pages, bring the summary pages, ledger pages, etc. Just bring it all.

Tip #4 – Print Your Books

Assuming you use a program like Quickbooks, print off a report covering your expenses or income in question. Although the auditor dismissed the report a few times as not being a validated report, I feel that it helped to add to the overall image of “I’m prepared” and “I’m not hiding anything.”

Tip #5 – Highlight Everything

It absolutely shocked and amazed my auditor that I had highlighted both the receipts and the bank statements. I highlighted the “total” and “date” on every invoice as well as each bank statement line item that made up the “Advertising” and “Other expenses” sections of my deductions. My auditor made statements like, “This is my favorite audit, ever!” before we had even started. Not only did I make her job easier, I made it obvious that I was hiding absolutely nothing.

Tip #6 – Handling Missing Data

I was surprised to learn, when researching how to handle the audit, that I didn’t have to have every single receipt/invoice I had claimed a deduction for. You will be expected to prove a majority of the deductions but the law allows for some instances of losing invoices, etc. You’re going to want to come as close to proving each deduction as possible, though. Some deductions can be validated without the actual receipts. Here are a few examples from my audit. Although I did not have receipts for an email newsletter ad I purchased with Entrepreneur magazine I still had the emails where they quoted me the price of the ad. Match this to the bank statement where I paid that exact amount and you have your proof. In the tax year in question I spent a considerable amount on Google Ads. I also spend a much smaller amount on Yahoo ads. Unfortunately, since Yahoo ads have shut down, I couldn’t sign in and print those invoices. But, explaining that I spent X on Google ads and Yahoo was the next biggest competitor I argued that it was reasonable that I would have spent 1/10th X on Yahoo ads. This was enough of an explanation to get the Yahoo deductions approved.

Conclusion

Don’t go into an audit with a chip on your shoulder. A computer chose you based on some valid triggers and now the auditor has to do their job. Each audit goes through a review and approval process, so each auditor is under pressure to not make mistakes. They aren’t out to “get” you, they just don’t want to fail in their own job performance. When my auditor began filing the paperwork to “fully allow” all of my expenses she physically felt ill and was extremely nervous. It was so rare that she was just afraid that she was missing something. It was only after consulting with peer auditors that she was able to confidently submit her report. Print everything, highlight everything, and take the steps to know that you’re right. If you’re not right, well, expect to pay the missing taxes as well as a penalty.

Jul 19, 2012 - Business    Comments Off

You’re Too Skinny

This is what your website looks like on a modern computer when you don’t redesign it for more than 10 years.

Relax…Stretch

Tirerack’s website fits within an 800px width. It is awkwardly jammed into the left-hand side of my screen. I checked Google Analytics on my own sites and found that PC screens with a width of 800px or less made up 5-6% of my visitors. I would argue that Tirerack would have a similar technologically advanced, but more male dominated, demographic. I have no idea why Tirerack has insisted on keeping this design when the web offers so much more.Why not stretch a little and make the site easier to use on today’s larger screens?

It Still Works

But, kudos to them for staying in business. In those 10+ years nobody has come up to even challenged their business. I’ve been buying tires from them for more than 10 years and always feel that I get a good deal. But, it’s fairly inexpensive, IMO, to update a website to a more modern layout; and it can only increase their revenue. If I were a stock holder I’d be asking why we are actively attempting to appear out-of-touch with the modern world. After all, buying tires via the web was a pretty bold, forward-thinking, concept when Tirerack launched. You would think they’d “get” it.

Jul 12, 2012 - Business    Comments Off

Websites Behind a Wall

The biggest website implementation mistake I see is still the Wall. People are just convinced that their offering is so enticing that people are going to be compelled to register just to find out if they’re truly interested in becoming a customer. This goes for free, freemium, and for-pay websites. I’m still shocked at the mistakes being made in this area. What’s the cause? Ego? Lack of creativity? There’s a solution.

In 2004 when I was doing research for my lost dog website idea I ran into a ton of websites behind a Wall. One in particular has stuck with me. The domain has since been sold (hint, hint, Walls suck) so I won’t link to it here. The website had a registration fee and a Wall. If you lost your dog you could pay to register and then you’d be able to search their found dogs list, etc. No public stats. No sample data. No idea if ANYONE was using the website (they weren’t). When I designed Fido Finder one of my ideas was to make it so obvious if/that it was used. And, I didn’t make people pay to register (that’s the mother Wall of them all, the Pay Wall).

Workarounds to the Wall

Groupon

Groupon.com is hidden behind a wall…if you visit their home page directly. The home page is a wizard walking you through picking your city and registering with your email address. You have no idea if they are offering anything you want. But, they have allowed for viral sharing. Their city pages are open to the public, if you know how to find them (Google). The Houston page shows current deals with details. The site also allows for direct linking to the individual deals themselves without having to be a registered member to view the deal. This allows for email sharing. Without this “window” on the side of their Wall, Groupon wouldn’t have the viral traffic that has made it a household name.


Groupon home page attempts to get you to climb the Wall


You can find city pages, though, if you Google for them, or are linked to them.

Fab

Fab.com has an interesting workaround for insisting that their products be behind a Wall. For example, Fab advertises its products on Facebook. If you click an ad you’re taken to a landing page that shows the page content in the background with a “register/login” overlay. You can see a dimmed content page behind the registration box. You can tell that this content is what you wanted to look at when you clicked the ad. It’s just enticing enough that you might consider registering in order to see more about this product. It’s an interesting compromise. Fab’s business model is built on the concept of emailing you daily product offerings. Their goal is to get access to your inbox to sell more products. For their concept to work you have to give up your email address. It worked, at least for me. Fab developed a glass Wall that I could see through. I could tell what was on the other side, and I wanted to be able to access it. So I gave up my email address. And now they email me every day and often I click their product links. Hautelook.com has a similar interface. You can view the current “events” from behind the tinted window. But if you want full access you have to register.


It’s behind a Wall, but I can see what it is!

Ideeli

Ideeli.com, another fashion deals website goes about skirting the Wall in a different manner. Ideeli first takes a shot at getting you to register on their home page. If you’re curious enough and click anywhere on the page (away from the registration box) you’re taken past the Wall, it seems. You now are viewing the product catalog. If you click through to a specific product you can now “add to cart”. When you try to add to your cart you are informed that you must be a registered user. Ahah! And this is not the same as a retail site asking you to create an account for checkout, you will be registering to receive daily/weekly deal emails. This interface is a good alternative to completely hiding behind the Wall.


Ideeli home page, click on the woman and you go to the catalog


It will appear as if you bypassed the Wall. You can see the products!


Click on a product and click “Add to Cart” and your shopping is abruptly stopped.

Klout

Klout.com is a website that measures your Internet reputation. Currently the only people that care about someone’s Internet reputation are those of us who have a Google alert set up with our own name. Nobody really looks someone ELSE up on Klout, do they? If you happened upon your own Klout profile, which is often generated based on public Twitter (etc) data before you ever visit, you would see something like the image below. You can see that Klout has information about you, and your friends / followers. If you were curious enough, you would be able to register to find out what else Klout knows about you. Klout wants you to register and connect to all of your social media accounts. Giving you a sample of the data they have about you is enticing enough for most to sign up. If you’ve made it far enough to find your Klout page you’ll probably register to see what’s behind the Wall.


This is the Klout Wall. But you can see through it. Register to see more.

Instagram

Instagram.com, by being a smart phone app, has a built-in Wall. You have to download the app in order to see what it really will offer you. The good thing about Instagram is that it’s built upon sharing. You can get an idea what the app offers simply by viewing other people’s photos that they have posted on Facebook and Twitter. Instagram wants you to register and follow these people within their app, sort of like following on Twitter. Most people have been introduced to what Instagram has to offer just by being a member of the Internet’s social media sites. Without this sharing push Instagram is just another behind the Wall photo filter app.

Conclusion

Putting a site behind the wall is most often a mistake. Getting traction for a site like this is expensive. Often the product offering isn’t good enough to support a Wall. Don’t assume that you’re website will be different from thousands of other failed sites behind a Wall. But if you need a Wall, consider some of these workarounds. Have a window and allow for social sharing to more than just your home page.

Jun 27, 2012 - Business    Comments Off

Facebook API: use publish_actions instead of publish_stream

Don’t use publish_stream, use publish_actions!

I was doing some research for Fido Finder’s Neighborhood Watch feature and I came upon the actual documentation for the different Facebook Graph API stream publishing permissions. I was shocked to find that every single HOW TO article I’ve read online is telling people to request the unnecessary publish_stream permission which actually requires the user to agree to additional permissions on a 2nd authorization screen (sound familiar?).

Publish_stream actually includes the publish_actions permissions and adds a few more permissions such as posting to a friend’s feed, posting questions, creating notes, and posting content to events or groups. If you do not need these 4 extra permissions then you DON’T NEED publish_stream. And, this means that users don’t have to agree to that scary “post to your feed” permission even though it’s actually included.

Every app I’ve ever authorized had a 2nd screen like:


The user can SKIP this permission!

If you use publish_actions you simply get the 1st screen:

Jun 26, 2012 - Business, Development    Comments Off

PHP Email Sending Guide

I have run into a lot of issues over the years getting my website-generated emails delivered to inboxes. Unfairly marked as SPAM, accidentally blocked by ISP’s, and occasionally lost in space. This guide is a collection of what I’ve learned about sending emails from PHP. I’m going to keep this entry updated as I learn more tips.

Use PHPMailer

I use PHPMailer which allows me to send emails by signing into the SMTP account/server (if you tell it to). I also have more control over headers, etc, with PHPMailer. When I switched to using PHPMailer/SMTP I noticed my messages not being marked as SPAM with certain email providers.

Send From Dedicated IP

Make sure your SMTP server does not share an IP address with others. If you host in a shared environment you’re out of luck. Even some dedicated server environments share an SMTP server (my old environment did, and I left). If your neighbor sends spam from the same server that you use for outgoing mail, your mail will likely be marked as SPAM, or worse, not delivered at all. Sometimes this lasts 24 hours, sometimes longer. Few businesses can risk not having their emails delivered.

Add DNS Entries

Email servers will check your DNS entries to make sure your outgoing IP is allowed to send mail for the domain.

  • Reverse DNS (rDNS / PTR) record -  Standard DNS resolves a domain name to an IP address. Reverse DNS resolves an IP address to a domain name. It says, OK 98.129.58.195, what’s your domain name? This is used to help determine the origin of the message and whether it matches the sending domain/address.
  • SPF (Sender Policy Framework) record – The idea behind an SPF record is for your domain server to be able to be queried and asked for a list of email servers that are allowed to send email for your domain. Even if you’re sending emails from the same server IP address, it helps to project to the email servers out there that your emails are allowed to be created from this IP address for your domain name.
  • DomainKeys and/or DKIM – Don’t be confused (by the Internet), these are two different, but similar, technologies DomainKeys and DKIM work in a public-key scenario, so a key is sent in the email that can be verified by querying the DNS server. Google it, or contact your webhost to find out how to set this up. It will be a combination of server settings and DNS entries. I was able to set up DomainKeys via Plesk but have not been able to figure out setting up DKIM.

HELO

Make sure your HELO, in the email header, does not show a different domain than the sending server. In my case, and maybe this is always true, when I finally got the HELO setup correctly the HELO message disappeared from the header, as it was no longer was needed. In my configuration I had to setup the HELO to match the sending server name which is not the domain of the email address. I set this in the PHPMailer config settings for HELO.

Odd SPAM Filters

  • Even if you’re sending mail from a do-not-reply address, you need to have a return address in the email headers. Many email hosts will not deliver mail that does not have a reply to address.
  • Do not obfuscate your HTML. Make sure it isn’t obvious that you created your HTML in code (one long line, etc).
  • Be careful with images. In one instance the occurrence of a simple logo at the top of outgoing emails led GMail to send the emails to the SPAM folder. Avoid them unless you need them.
  • Don’t use words like “100% guaranteed”, “as seen”, or an all caps subject.
  • Look through SpamAssassin header rule codes to learn more.

Handle Bounced AND Rejected Emails

  • Bounced – Some mail will be bounced back to you at a later time/date. Set up VERP for outgoing emails. This will mean adding a header of “return-path” to outgoing emails that includes the receiving email address in a specially formatted string. This string appears to be an email address at your domain but in reality routes to your catch-all email box. Then, you have your server set to pipe all mail to the catch-all box to a PHP script. The special string looks like user=domain.com@yourwebsite.com. You can parse this string and discover what address you emailed that bounced back. In PHPMailer I had to modify the code to allow for a new property called “returnpath” and I modified the code where PHPMailer sets the returnpath header value. Email me for more info.
  • Rejected – Some mail will fail to send immediately, but PHPMailer won’t know this (for whatever reason). Since your MTA will email you a rejection notice, have all of your email sent to your do-not-reply address piped to the same script. When your MTA sends you a failed delivery notice you will want to process this message and add the email address to your do-not-email database table.
  • Here is a link to my php email bounce script. I found this online and modified it over the years.

Sign up for Feedback Loops

The major mail providers and ISPs offer a feedback loop. Feedback loops allow the mail providers to alert you when a user reports your messages as SPAM. You can then act accordingly (stop emailing them?). Here is a list of some of the available feedback loops.

Pages:1234567»