SparkPost enables you to send email at scale, including HTML (and AMP HTML) that has linked images. In this article, Casey covered the best practices for using images, audio and video on your website and emails from a marketing, reusability and accessibility perspective. Unlike some “full fat” ESPs, we don’t actually store and serve the image files for you. Fear not! There are many options:

  • Serving images directly from your own website – perhaps the easiest way to use your own image assets.
  • Amazon Simple Storage Service (S3)
  • Google Cloud Storage
  • Azure Blob Storage

Github can serve “raw” digital assets such as images, and it’s free. We use this for our template examples – the repo here has images that are served via links, like this picture of an avocado).

Your favorite service really comes down to cost, reliability, ease of use, and performance. The performance your end-users see depends mostly on whether your service uses (or can be configured to use) a Content Delivery Network – usually known by the acronym CDN – that caches and delivers the images for you.

The larger CDNs have many points of presence spread geographically, so that the round-trip time is as fast as possible between your recipients opening the mail, and the image being delivered back.

Introducing Orlando the cat

For this article, we’ll play with a sample image, served from an S3 bucket. I sized this image file to be 1024 pixels wide, which should be about right for email viewing. I’m using the PNG file format here, although JPG would also be OK.

Setting up S3 to serve images and static websites is beyond the scope of this article; here and here are starting points. You need to take care on what you are making public, and it’s important never to allow public write permissions to your buckets or objects. Here’s my object URL:

Click, and it opens in your browser. He’s named after the Orlando of childhood stories, in case you were wondering – not this place or this actor.

HTTPS everywhere, soon

You’ll notice that S3 gave us an HTTPS image address. There are initiatives to move as much as possible of the Internet to HTTPS and avoid “mixed content” – such as Google, LetsEncrypt for free certificates, the Electronic Frontier Foundation’s “HTTPS everywhere”.

SparkPost supports AMP for email HTML. AMP requires HTTPS for content.

One good, quick way to check your HTTPS support, is to put your image URL into the SSL Labs test page. This takes a few minutes to run, and gives you results for the site not the individual image, so one test is enough. Here’s what they have to say about our Amazon S3 bucket:

We get a “B” rating, because S3 is happy to serve with outdated TLS protocol versions. I assume it’s done for maximum compatibility with those really terrible obsolete browsers that your grandparents use!

Looking deeper with Chrome Developer Tools

The Chrome browser has a nifty feature called Developer Tools, which enables you to see a timeline of your browser fetching the image. On Mac OSX, it’s on the menu View / Developer / Developer Tools.  On Windows and OSX, it’s on the “three dots” menu top right / More Tools / Developer Tools.

When you refresh the browser to fetch the image, then select “Network”, Developer Tools shows a timeline of the request. The green and blue bar shows the time spent waiting, and the time downloading the image file to your browser.

On Windows 10, Chrome Developer Tools gives the same kind of view. The vertical divisions between image and waterfall chart can easily be resized, so you can zoom in on details..

Firefox Developer Tools

If you prefer Firefox, it has similar tools. On OSX and Windows, open the “three lines” menu top right / Web Developer / Toggle Tools. You’ll see a similar view under “Network” when you refresh the image.

If you look closely, you’ll see the browser also tried to fetch the file “favicon.ico”, but it was not found. This is usual browser behavior, and you’d typically have a favicon file on a real site.

Checking certificates with Chrome and Firefox

We can also use the browser to check which certificate is being used by the site. On Chrome, click the padlock icon next to the site address:

Click on the “Certificate (Valid)” wording, and we can see more.

Clicking “Details” will show more information on the certificate itself.

In Firefox, click the padlock (not the shield next to it):


Click the > symbol:

Click on “More Information”, and you’ll see a separate window, similar to the Chrome “Details” view.

In production you will typically be using your own certificate, either served directly from your website or mediated by your CDN.

Now let’s look at how we can see that detailed information from the command-line. That would enable you to have a script that periodically checks all your images are available, and are being served with good security.

Diving deeper with curl

Curl is a great all-purpose HTTP tool that is available for many platforms, including OSX, Windows, and Linux. You’ll probably only need this section if you’re seeing errors from your image server, and that’s hopefully rare .. anyway, here goes the deep-dive part.

Mac OSX curl

On Mac OSX, you can pipe Curl output straight into the standard image Preview application, using the very useful open command to trigger the application.

curl -v | open -a -f

The -a option names the app to use, and -f specifies that the input should come from stdin, in other words the piped output from curl.

The curl -v option means “verbose”, giving us a view into the TLS handshake and certificate exchange that happens as the HTTPS connection is made. Here’s the details, broken up with some commentary.

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                               Dload  Upload   Total   Spent    Left  Speed
0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*  

This bit is the upload progress meter. Nothing has happened, yet, so it shows zero.

* Connected to ( port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [91 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [3234 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [333 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [70 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol

Our client offered TLS v1.3, but our server selected TLSv1.2 instead.

Our server isn’t offering ALPN but it’s fine, the conversation proceeds using HTTP 1.1.

* Server certificate:
*  subject: C=US; ST=Washington; L=Seattle;, Inc.; CN=*
*  start date: Nov  9 00:00:00 2019 GMT
*  expire date: Dec 10 12:00:00 2020 GMT
*  subjectAltName: host "" matched cert's ""
*  issuer: C=US; O=DigiCert Inc;; CN=DigiCert Baltimore CA-2 G2
*  SSL certificate verify ok.
} [5 bytes data]

This is a summary of the certificate offered by the server. DigiCert Inc is the certificate authority, and the host we are talking to is Amazon S3, EU-West-1.

The certificate is verified against the trusted “certificate bundle” held locally on my Mac, which was earlier shown to be in /etc/ssl/cert.pem. For more information on how certificates are validated using the chain of trust, this article is a good place to start.

> GET /tuck1s.imagehosting/cat_in_bag.png HTTP/1.1
> Host:
> User-Agent: curl/7.69.1
> Accept: */*
{ [5 bytes data]

The lines marked > is the request made from client to server.

* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< x-amz-id-2: q1U9CPAGAHiJDeUhZJQ/QuPPYiZmvhhhUlSf1td1mq6N6gESfk9gB42IN5+pfZbp90AnfHx6rZE=
< x-amz-request-id: B048E4F5668AD383
< Date: Wed, 08 Apr 2020 17:19:55 GMT
< Last-Modified: Wed, 08 Apr 2020 09:28:52 GMT
< ETag: "ca62ee207f5172ac66cbc663bee21375"
< Accept-Ranges: bytes
< Content-Type: image/png
< Content-Length: 984815
< Server: AmazonS3

Details you can skip: the “Mark bundle” line is a result of agreeing HTTP 1.1, rather than HTTP/2.

The lines marked < are the server response headers, showing that we’re about to receive a chunk of data.

{ [5 bytes data]
100  961k  100  961k    0     0  2747k      0 --:--:-- --:--:-- --:--:-- 2747k
* Connection #0 to host left intact

This last part shows the progress meter, after the transfer succeeded. It probably happened so fast that you never saw it gradually change.

If for some strange reason you want to slow down the transfer just so you can see it happening, there’s a --limit-rate option, you can use. For example, --limit-rate 56k makes the connection run at the speed of mid-1990s dial-up Internet!

Windows curl

On Windows, once you have curl installed, it works much the same; except the standard image viewer mspaint.exe doesn’t play nicely with pipes. You can direct the output into a temporary file, then open mspaint32.exe:

C:\curl-7.69.1-win64-mingw\bin>curl -v --output test.png

C:\curl-7.69.1-win64-mingw\bin>mspaint.exe test.png

Linux curl

Linux usually comes with curl baked in. If not, it’s easy to install from your package manager.

Viewing graphical files on Linux is possible if you have a windowing environment. Here’s an example, from an old laptop of mine running Linux Mint 19.2 Cinnamon. I installed the ImageMagick package, which includes an image viewer tool called “display”.

sudo apt install -y imagemagick

We can easily pipe into this tool.

curl -v | display


In this article, we’ve seen how to investigate and diagnose image services (in fact, any content), using:

  • Chrome Developer Tools
  • Firefox Web Developer Tools
  • For the ultimate geek-fest, curl shows detailed information on the behavior of your image service, including client-server TLS handshake, certificate exchange, and HTTP(S) protocol. We saw how you can pop the fetched image up in a preview window, on OSX, Windows, and Linux.

I hope these tools and tips will help you get the most out of your image services. You can get in touch on Twitter via @SparkPost, we’d love to hear from you.

~ Steve