<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>BIMI &#8211; Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/tag/bimi/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Sat, 07 Jun 2025 16:31:15 +0000</lastBuildDate>
	<language>en-GB</language>
	<copyright>© Terence Eden. 🄯 CC BY-SA. See https://shkspr.mobi/blog/copyright-and-copyleft/</copyright>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>BIMI &#8211; Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Getting lots of BIMI images using Python]]></title>
		<link>https://shkspr.mobi/blog/2024/06/getting-lots-of-bimi-images-using-python/</link>
					<comments>https://shkspr.mobi/blog/2024/06/getting-lots-of-bimi-images-using-python/#respond</comments>
				<dc:creator><![CDATA[Terence Eden]]></dc:creator>
		<pubDate>Fri, 07 Jun 2024 11:34:09 +0000</pubDate>
		<category><![CDATA[BIMI]]></category><category><![CDATA[DNS]]></category><category><![CDATA[svg]]></category>		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=50701</guid>

					<description><![CDATA[I&#039;ve written before about the moribund BIMI specification. It&#039;s a way for brands to include a trusted logo when they send emails.  It isn&#039;t much used and, apparently, is riddled with security issues.  I thought it might be fun to grab all the BIMI images from the most popular websites, so I can potentially use them in my SuperTinyIcons project.  BIMI images are SVGs. Links to a site&#039;s BIMI are…]]></description>
										<content:encoded>&lt;p&gt;I've written before about the &lt;a href="https://shkspr.mobi/blog/2022/08/dns-esoterica-bimi-svg-in-dns-txt-wtf/"&gt;moribund BIMI specification&lt;/a&gt;. It's a way for brands to include a trusted logo when they send emails.  It isn't much used and, apparently, is &lt;a href="https://mailarchive.ietf.org/arch/msg/bimi/xzYRH72V2HE9xeUfXK_zUgYSI7k/"&gt;riddled with&lt;/a&gt; &lt;a href="https://mailarchive.ietf.org/arch/msg/bimi/PS8Xf1hQ41oCAwtsUvVsbRSs34Q/"&gt;security issues&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I thought it might be fun to grab all the BIMI images from the most popular websites, so I can potentially use them in my &lt;a href="https://shkspr.mobi/blog/2020/05/some-updates-to-supertinyicons/"&gt;SuperTinyIcons project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;BIMI images are SVGs. Links to a site's BIMI are stored in a domain's DNS records.  All BIMI records &lt;em&gt;must&lt;/em&gt; be on a &lt;code&gt;default._bimi.&lt;/code&gt; subdomain.&lt;/p&gt;

&lt;p&gt;If you run &lt;code&gt;dig TXT default._bimi.linkedin.com&lt;/code&gt; you'll receive back:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-dns"&gt;;; ANSWER SECTION:
default._bimi.linkedin.com. 3600 IN TXT "v=BIMI1; l=https://media.licdn.com/media/AAYQAQQhAAgAAQAAAAAAABrLiVuNIZ3fRKGlFSn4hGZubg.svg; a=https://media.licdn.com/media/AAYAAQQhAAgAAQAAAAAAALe_JUaW1k4JTw6eZ_Gtj2raUw.pem;"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Awesome! We can grab the &lt;a href="https://media.licdn.com/media/AAYQAQQhAAgAAQAAAAAAABrLiVuNIZ3fRKGlFSn4hGZubg.svg"&gt;.svg URl&lt;/a&gt; and download the file.&lt;/p&gt;

&lt;p&gt;Getting a list of BIMI enabled domains is difficult. Thankfully, &lt;a href="https://www.uriports.com/blog/bimi/"&gt;Freddie Leeman has done some excellent analysis work&lt;/a&gt; and was happy to share &lt;a href="https://pastebin.com/si9e8dCc"&gt;a list of over 7,000 domains which have BIMI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's get cracking with a little Python.  First up, &lt;a href="https://www.dnspython.org/"&gt;install DNSPython&lt;/a&gt; if you don't already have it.&lt;/p&gt;

&lt;p&gt;This gets the TXT record from the domain name:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import socket
import dns.resolver

response = dns.resolver.query('default._bimi.linkedin.com', 'TXT')
result = response.rrset.to_text()
print(result)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are various ways of extracting the URl. I decided to be lazy and use a regex. Sue me.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import re

pattern = r'l=(https[^;"]*[;"])'
match = re.search(pattern, result)
if match:
   # Remove the trailing semicolon or quote mark
   url = match.group(1).rstrip(';\"')
   print(f'Matched URL: {url}')
else:
   print(f'No match: {result}')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Putting it all together, this reads in the list of domains, finds the BIMI TXT record, grabs the URl, and saves the SVG.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-python"&gt;import socket
import dns.resolver
import re
import requests

headers = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0'
}

pattern = r'l=(https[^;"]*[;"])'

domain_file = open('domains.txt', 'r')
domains = domain_file.readlines()
domains.sort()

for domain in domains:
   bimi_domain = "default._bimi." + domain.strip()
   try:
      response = dns.resolver.query(bimi_domain, 'TXT')
      result = response.rrset.to_text()
      match = re.search(pattern, result)
      if match:
         # Remove the trailing semicolon or quote mark
         svg_url = match.group(1).rstrip(';\"')
         print(f'Downloading: {svg_url}')
         try:
            svg = requests.get(svg_url, allow_redirects=True, timeout=30, headers=headers)
            open(domain.strip() +'.svg', 'wb').write(svg.content)
         except:
            print(f'Error with {domain}: {result}')
      else:
         print(f'No match from {domain}: {result}')
   except:
      print(f'DNS error with {bimi_domain}')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously, it could be made a lot more efficient and download the files in parallel.&lt;/p&gt;

&lt;p&gt;I found a few bugs in various BIMI implementations, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ted.com and homeadvisor.com uses a &lt;code&gt;http&lt;/code&gt; URl&lt;/li&gt;
&lt;li&gt;consumerreports.org and sleepfoundation.org has a misplaced space in their TXT record&lt;/li&gt;
&lt;li&gt;audubon.org had an invalid certificate&lt;/li&gt;
&lt;li&gt;mac.com was blank - as was discogs.com, livechatinc.com, icloud.com, me.com, lung.org, miro.com, protonmail.ch and many others.&lt;/li&gt;
&lt;li&gt;alabama.gov had a timeout - as did nebraska.gov, uclahealth.org and several others.&lt;/li&gt;
&lt;li&gt;politico.com had a 404 for their BIMI - as do &lt;em&gt;lots&lt;/em&gt; of others.&lt;/li&gt;
&lt;li&gt;coopersurgical.com is 8MB!&lt;/li&gt;
&lt;li&gt;There are &lt;em&gt;loads&lt;/em&gt; of SVGs which bust the &lt;a href="https://bimigroup.org/creating-bimi-svg-logo-files/"&gt;32KB maximum size requirement&lt;/a&gt; - some by multiple megabytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I might spend some time over the next few weeks optimising the code and looking for any other snafus. I didn't find any with ECMAScript in them. Yet!&lt;/p&gt;
&lt;img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=50701&amp;amp;HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager"&gt;</content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/06/getting-lots-of-bimi-images-using-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
