This has been nagging me for a long time, and I just found a fix! 

OK, so there are a lot of words in the title. All very Microsoft-y. I promise you, I’m writing this post on Chrome on Linux (Debian, to be exact. Screenshots available upon request.)

This post is for people who:

  • Use Office365 Groups to collaborate with, well, groups
  • Use SharePoint Document Libraries provided by Groups
  • Wish to share documents from SharePoint without requiring a login (in Microsoft language, this is considered external sharing to non-authenticated users)


…or, a Defense of Office 365 Groups and SharePoint, plus a rantlet

One of my favorite things about Office 365 is how Microsoft rolls out enhancements, new features, and bug fixes in a steady, transparent way. (I love the public roadmap.) I was very interested last year when Microsoft announced Groups as a simple way to collaborate with colleagues, including: shared conversations, document storage, calendar, notebook, and more. I decided to roll the dice and leverage Groups to support a particular organization I volunteer with. By and large, it’s been … OK. There was one rather painful issue that we resolved a few months back, but this post is not about that.

Sometimes new products from Microsoft can feel like a tangle of technologies that are generally (but not fully) coherent. There is overlap (“Hi, thanks for trying to sign in. Are you using a work/school account, or a Microsoft account?”); there is some instability (“We’re having issues, but we’re working on it.”)… Then there is a class of problems that (being kind) I will blame on having to support many different technologies — some legacy, some new — and it goes like this:

New feature A works great! Unless you’re also using Feature B, in which case Feature A doesn’t work at all. Unfortunately, we’ve been busy and we haven’t updated the documentation yet to reflect this, so we’ll give you a generic error message to puzzle through.

I seem to be pretty good at finding these issues.

The Issue – Sharing to “Anyone” is Blocked

With this organization, we have our core group of collaborators who have read/write access to content, and we need to share content with people outside the organization (external users) several times a year. The access should be read-only and it should not require a Microsoft account (or a Work/School account). If it’s able to use SharePoint’s auto-expiring links, even better. Those are cool.

Here’s what I see when I attempt to share something from the document repository:

Screenshot of Office 365 SharePoint Online External Sharing dialog

No sharing for you.

I searched and found lots of references to turning on external sharing in SharePoint Online. I checked many checkboxes that said things like “enable external sharing for all your sites!”, but somehow the option was never available to me here in this SharePoint library.

As you may have guessed — the documentation applied to SharePoint Online — but not when using it through Office 365 Groups. Ugh.

The Solution – PowerShell

I get an email once a week or so from Office 365 telling me about new features. Most recently, there was something that touched on sharing privileges in Groups. It got me thinking about this problem again, and I started looking for a solution. I came across a document (have I seen this document before? maybe in a frenzy of tabs when searching for this solution before?) that contained the answer, clear as crystal: 

The answer is PowerShell. The Cliffs Note version of the update is:

  1. Install the SharePoint Online Management Shell. That is unless you’re cool enough to already have it installed.
  2. Connect to your environment using the Connect-SPOService cmdlet.
  3. (optionally) Get your site’s current settings. I always like to see what I’m updating before I update it:
    (Get-SPOSite -Identity
  4. Perform the update. The SharingCapability you want is ExternalUserAndGuestSharing:

    Set-SPOSite -Identity -SharingCapability ExternalUserAndGuestSharing

And you’re set. Link expiration too!! Here’s the proof:

Screenshot of Office 365 SharePoint Online External Sharing dialog


I just spent a few hours troubleshooting this issue with running WordPress on Azure. I didn’t find anything helpful online, so I figured I’d share. This post is for people who:

There have to be some people out there who do this too, right??

The Issue – Failing Imports

If you use Microsoft’s Azure App Service to host your WordPress solution, you may have heard about WinCache:

Windows Cache Extension for PHP is a PHP accelerator that is used to increase the speed of PHP applications running on Windows and Windows Server. Once the Windows Cache Extension for PHP is enabled and loaded by the PHP engine, PHP applications can take advantage of the functionality without any code modifications.

I’ve found that enabling and configuring WinCache makes the largest improvement in WordPress performance on Azure short of page caching. It provides a big boost without the (shall we say) considerations of page-level caching.

However, it does seem that WinCache’s file caching in particular throws off WP All Import. I dug into the code a bit, and it appears that CSV uploads are converted to XML, which are output to disk and then immediately read back for processing. When WinCache’s file cache is enabled, this read-back is blank. As a result, WP All Import has no data to work with. Imports run but don’t import any data.

Importantly, even previews fail, which is how I was able to quickly test for the problem. I uploaded a trivial CSV file with the following info:




I configured a simple import to use Col1 as title and Col2 as Body, click preview, and the title field is busted:

Screenshot of WP All Import showing warning

Strangely, when I close the preview window and click to preview again, now Content is busted too!

Screenshot of WP All Import showing two warnings

Feels like a timing issue.

Workaround – Temporarily Disable WinCache File Cache

I added the following directive to the .ini file I used to configure WinCache, with a note reminding me to tweak this before and after an import. We’ll see if I remember to do that…

; uncomment before performing import with wp all import

Don’t forget to restart your app before attempting the import again. Once done, preview (and import) work successfully:

Screenshot of WP All Import showing no warnings


magnified screen showing an email icon

Life as a Compulsive Domain Collector

I seem to have accumulated a number of domains over the years. A couple of them are important to me, such as this very domain, plus the domain I use for my personal email, but most just kind of hang out in the ether. My credit card is pinged once per year per domain for the privilege of keeping these unused virtual assets.

I let a number of domains lapse over the past couple of years, based on the compelling historical evidence that I do very little with them. Occasionally, though, I still come up with (what feels like) a clever name for something that is real or imagined, check to see if the domain is available, and lock it in.

For example, just a few weeks ago I bought two amazing domains — and the tamer I try to bring a calm clarity and focus when I work with small companies. I pursue what you might call the “sane startup”. Maybe I’ll have some fun with those two domains.

Email as a Service Means $$$

For each of these domains, I want a least one email address and some aliases. Something like, for example, so I can tell them where to send the checks when the bidding war for this awesome domain begins. And I’ll want to add an alias for webmaster@, since that was standard practice last time I checked (which may have been 1998). Are “webmasters” still a thing? Oh, God … am I a webmaster?

OK, so you have your shiny new domain and you want an email address. How do you do it?

There used to be an amazing solution, which to me was the hands-down way to go — that would be Google Apps, (now Google Apps for Work), back when it was free. Imagine! Email addresses for your custom domain and tools to manage your organization, all free. It was like email utopia.

Alas, it is no longer free. It now costs $5/user/month. It’s worth it for a for-real organization and domain, considering the quality of the service. But $120/yr just to have an info@ email addresses at these two domains doesn’t make sense to me.

I did some (admittedly light) research and came to the conclusion that email addresses cost about $5/month, roughly speaking, so that’s what I used for my calculations. Coincidentally, I did find one provider ( that offers free email for a custom domain. There are limits, as you’d expect, but most other “free” providers I saw merely offer a free trial.

As you can probably guess from the title of this article, the approach I picked was to run my own email server in the cloud. You can, too.

The good:

  • Free for the first year! (new AWS subscription and baby tiny VM)
  • No incremental cost for adding domains
  • Lots of configurability
  • Flexes my devops nerd muscles

The bad:

  • Not cost effective until you host a couple of domains
  • Have to monitor/manage the VM availability and performance
  • Have to monitor/manage mailability from the VM’s IP

AWS VS. Azure

I don’t really do religious wars anymore over things like cloud platforms. The way I look at it, most tools will get the job done. Some tools are better suited than others for particular jobs. In each case, the implementer’s experience and comfort level with a given tool is a critical factor.

That being said, I happen to have worked with Microsoft Azure quite a bit over the past couple of years, and there are a few reasons it’s my go-to cloud platform for this kind of work. I won’t get into that here, but if you’re curious, leave a comment and I’ll add some more detail.

Anyway, it doesn’t matter. I went through the process of deploying and configuring my mail server on Azure, only to realize that port 25 is blocked, no exceptions. Which is to say: you can’t run an email server on Azure. I found it hard to believe at first, so I followed up with Microsoft support. Here is (part of) the reply:

“Sending outbound e-mail to external domains (such as,, etc) directly from an e-mail server hosted in Azure compute services is not supported due to the elastic nature of public cloud service IPs and the potential for abuse. As such, the Azure compute IP address blocks are added to public block lists (such as the Spamhaus PBL). There are no exceptions to this policy.”

Wow, preemptively putting their IPs on spam blacklists? That’s intense. I don’t fault Microsoft for that choice, but it did send me down the AWS path. Fortunately, Amazon’s platform is much more accommodating for this type of workload.

A Note on Email Server Etiquette

To put it simply — don’t don’t don’t don’t don’t send spam.

I could really just leave it at that, I suppose. I could also add a clarifying example, like — don’t buy a list of email addresses from the internet and send a marketing email to that list using your new mail server. Or any server, to be clear. That’s extremely rude. Plus, if you did it after setting up an email server using these instructions, I would feel responsible. I’ve got enough on my plate, thank you.

Keep in mind – not only is it rude, but (in case you are unfamiliar with sending a decent quantity of email), your IP will end up on one or more global blacklists, and that will probably prevent your email from being delivered. From the very handy

What is an IP or domain blacklist problem?

A blacklist, also known as DNSBL or RBL (DNS Blacklist or Realtime Blacklist respectively) is a spam blocking list, that can prevent your mail server from sending email. If you find your mail server has been blacklisted, some email you send may never be delivered. Currently, there are more than 100 organizations that run these lists and each one has different specifications for adding your domain or ip to their list.

This is important to keep in mind when building out an email server in the cloud. There is a chance that you’ll obtain a blacklisted IP for your system. The approach I took (and which I’ll describe in detail in the next installment) was to allocate a static IP (what AWS calls an Elastic IP), check to make sure it wasn’t blacklisted, and plan to hang onto it.

To prevent shenanigans, AWS by default will throttle port 25 traffic, but they do have a form where you can request that they lift these limitations. I submitted and was approved within a couple of hours.

Cost of the AWS Implementation

I’ve always found it challenging to estimate the cost of a cloud deployment. There are calculators out there (like Amazon’s “simple” monthly calculator), but you have to know things like how many gigabytes per month of outbound traffic you expect. Um, I’m really not sure. Fortunately, this should be a very low volume service, so I feel comfortable guessing low numbers.

Here’s what I spec’d out:

  • EC2: Linux t2.micro instance – always on, no contract
  • S3: 20GB EBS gp2 storage
  • 1 GB outbound data

Works out to $11.52/month, once the free tier period is up. I could even cut that about in half if I committed to a year up front. Maybe I’ll try that when I’m out of the free zone. But you can see how, since there is no incremental cost for adding domains, you only need about 2 domains for this exercise to be worth it (based on AWS cost, anyway. If you account for your time strictly, the math changes).

Implementation Steps

In Part 2 (coming soon), I’ll describe in detail the steps I took to implement my server.