<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Daniel Mitchell]]></title><description><![CDATA[I'm Daniel Mitchell, a Senior Software and Cloud Engineer based in the UK.]]></description><link>https://www.daniel-mitchell.com/</link><image><url>https://www.daniel-mitchell.com/favicon.png</url><title>Daniel Mitchell</title><link>https://www.daniel-mitchell.com/</link></image><generator>Ghost 4.36</generator><lastBuildDate>Mon, 04 May 2026 17:26:40 GMT</lastBuildDate><atom:link href="https://www.daniel-mitchell.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[The Perils of test.php: How a Simple File Led to a Spam Nightmare]]></title><description><![CDATA[<p>In the world of web development, we&apos;ve all deployed throwaway files for debugging&#x2014;often with innocent names like <code>test.php</code>. But sometimes, these small conveniences can snowball into major security breaches.</p><p>One such case involved a <code>test.php</code> file containing a single, seemingly harmless line of code:</p>]]></description><link>https://www.daniel-mitchell.com/blog/the-perils-of-test-php-how-a-simple-file-led-to-a-spam-nightmare/</link><guid isPermaLink="false">686247b022fd18542d8b2d43</guid><category><![CDATA[PHP]]></category><category><![CDATA[Security]]></category><category><![CDATA[Email]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Mon, 30 Jun 2025 08:22:14 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2025/06/A-banner-image-illus---Copy-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2025/06/A-banner-image-illus---Copy-1.png" alt="The Perils of test.php: How a Simple File Led to a Spam Nightmare"><p>In the world of web development, we&apos;ve all deployed throwaway files for debugging&#x2014;often with innocent names like <code>test.php</code>. But sometimes, these small conveniences can snowball into major security breaches.</p><p>One such case involved a <code>test.php</code> file containing a single, seemingly harmless line of code:</p><pre><code class="language-PHP">&lt;?php phpinfo(); ?&gt;</code></pre><p><strong>What&#x2019;s the Harm in <code>phpinfo()</code>?</strong><br>At first glance, <code>phpinfo()</code> is a useful tool. It provides detailed information about your PHP configuration, environment variables, installed modules, and more. But that&#x2019;s also <em>exactly</em> why it&#x2019;s dangerous.</p><p>When <code>test.php</code> was deployed and left publicly accessible, it revealed sensitive <strong>environment variables</strong> to anyone who visited the URL. Among those were <strong>AWS SES credentials</strong>&#x2014;tokens that granted programmatic access to Amazon&#x2019;s Simple Email Service.</p><p><strong>The Consequence? Weaponized Infrastructure</strong><br>An attacker discovered the file, harvested the credentials, and used them to integrate AWS SES into a mailer service. From there, they sent out a tidal wave of spam emails&#x2014;all under the banner of the legitimate SES account. That not only led to a compromised sender reputation, but could have triggered account suspension, blacklisting, or even regulatory action depending on the volume and content of those messages.</p><p><strong>Key Takeaways for Developers and Ops Teams:</strong></p><ul><li><strong>Never expose <code>phpinfo()</code> or debugging tools in production.</strong> Use secure environments and authentication barriers for diagnostics.</li><li><strong>Audit all public files before deployment.</strong> Even a single overlooked file can undo years of careful engineering.</li><li><strong>Use scoped IAM roles</strong> and <strong>do not store credentials in environment variables</strong> that are accessible by the web server.</li><li><strong>Set up alerts</strong> and <strong>rotate credentials regularly</strong>&#x2014;a single leak shouldn&#x2019;t mean total compromise.</li></ul><p><strong>&#x1F575;&#xFE0F; Other Files Scammers Commonly Hunt For</strong></p><p>Bad actors often use automated scanners to sweep the internet for exposed files that can leak credentials, configurations, or system insights:</p><!--kg-card-begin: html--><table><thead><tr><th><p>File/Endpoint</p></th><th><p>Risk Description</p></th></tr></thead>
<tbody><tr><td><p><code>/phpinfo.php</code> or <code>/info.php</code></p></td><td><p>Same as <code>test.php</code>, exposes server configs and env variables</p></td></tr>
<tr><td><p><code>.env</code></p></td><td><p>Contains environment variables like database credentials, API keys</p></td></tr>
<tr><td><p><code>.git/config</code> or <code>.git/HEAD</code></p></td><td><p>Exposes Git repo internals, possibly allowing full source code download</p></td></tr>
<tr><td><p><code>config.php</code>, <code>db.php</code></p></td><td><p>Often contain DB login credentials hardcoded for convenience</p></td></tr>
<tr><td><p><code>backup.zip</code>, <code>site.tar.gz</code>, <code>db.sql</code></p></td><td><p>Accidental backups of full systems or databases</p></td></tr>
<tr><td><p><code>composer.json</code> / <code>composer.lock</code></p></td><td><p>Can reveal package dependencies with known vulnerabilities</p></td></tr>
<tr><td><p><code>/admin/</code> directories</p></td><td><p>Common brute-force targets for admin panel access</p></td></tr>
<tr><td><p><code>.DS_Store</code>, <code>Thumbs.db</code></p></td><td><p>Leak directory structure and sometimes sensitive filenames</p></td></tr>
<tr><td><p><code>/server-status</code> (Apache)</p></td><td><p>Provides live metrics about server load and connections (if enabled)</p></td></tr>
</tbody>
</table><!--kg-card-end: html--><p>Some scanners even look for misconfigured CI/CD pipelines, logs, or temporary test scripts named <code>debug.php</code>, <code>temp.php</code>, or <code>sandbox.php</code>.</p><p>Debugging should never come at the expense of security. In this case, one line of PHP script created a gateway for exploitation. The next time you&#x2019;re tempted to drop a <code>test.php</code> onto the server for a quick check&#x2014;pause and think of the spam tsunami that might be lurking behind it.</p>]]></content:encoded></item><item><title><![CDATA[Sign ASL Year Review 2024]]></title><description><![CDATA[<p>2024 saw new peaks in usage for the sign language dictionary, www.signasl.org. With a whopping <strong>34,412,937 searches</strong> conducted on the platform and <strong>908,000 unique visitors.</strong> This was a <strong>6.8% increase</strong> from 2023, which had 32,197,037 searches. This continued growth speaks to our</p>]]></description><link>https://www.daniel-mitchell.com/blog/sign-asl-year-review-2024/</link><guid isPermaLink="false">67bb56b922fd18542d8b2cfd</guid><category><![CDATA[SignASL]]></category><category><![CDATA[Year in Review]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Wed, 15 Jan 2025 17:11:00 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2025/02/1000030579-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2025/02/1000030579-1.png" alt="Sign ASL Year Review 2024"><p>2024 saw new peaks in usage for the sign language dictionary, www.signasl.org. With a whopping <strong>34,412,937 searches</strong> conducted on the platform and <strong>908,000 unique visitors.</strong> This was a <strong>6.8% increase</strong> from 2023, which had 32,197,037 searches. This continued growth speaks to our commitment to providing comprehensive resources for those learning American Sign Language.</p><h4 id="top-50-words-searched">Top 50 Words Searched</h4><p>Our top searched words for 2024 reflected both everyday conversation essentials and some intriguing trends:</p><ul><li>Pro</li><li>Have</li><li>Good</li><li>Like</li><li>What</li><li>Want</li><li>Love</li><li>When</li><li>How</li><li>You&apos;re Welcome</li><li>Do</li><li>School</li><li>Happy</li><li>Thank You</li><li>Where</li><li>To</li><li>And</li><li>With</li><li>Go</li><li>Translate</li><li>For</li><li>Play</li><li>Is</li><li>Help</li><li>Need</li><li>Why</li><li>Hello</li><li>We</li><li>How Are You</li><li>Dog</li><li>Favorite</li><li>Work</li><li>Please</li><li>No</li><li>I</li><li>Nazi</li><li>You</li><li>Can</li><li>All</li><li>Brother</li><li>Now</li><li>Not</li></ul><h4 id="upgraded-ios-asl-app">Upgraded IOS ASL App</h4><p>We&#x2019;re thrilled to announce the launch of our upgraded IOS ASL app, packed with user-friendly features to enhance your experience:</p><ul><li>New tabbed interface for easy navigation</li><li>Access to Recent and Popular signs</li><li>Option to hide video controls overlay</li><li>Loop video playback for continuous learning</li><li>Back and forward buttons in the video player for quick access to alternative signs</li><li>Ability to continue audio playback from other apps while watching videos</li><li>Show video attribution to credit content creators</li><li>Save your favorite signs and view them offline</li><li>Support for dark mode to reduce eye strain</li><li>Improved startup behavior for better offline access</li></ul><p>A special thanks to <strong>Mat Gadd</strong> for the incredible update! We couldn&#x2019;t have done it without you.</p><p>As we move forward, we&#x2019;re excited to continue providing improving the video dictionary. Stay tuned for more updates and happy signing!</p>]]></content:encoded></item><item><title><![CDATA[Sign BSL Year Review 2024]]></title><description><![CDATA[<p>Greetings, British Sign Language enthusiasts!</p><p>We&apos;re excited to share an incredible milestone in our journey to promote and support sign language learning. As we reflect on the year 2024, we&#x2019;re thrilled to report some fascinating insights and achievements from www.signbsl.com.</p><p><strong>Record-Breaking Searches: </strong>In 2024,</p>]]></description><link>https://www.daniel-mitchell.com/blog/sign-bsl-year-review-2024/</link><guid isPermaLink="false">67b9c54022fd18542d8b2c9e</guid><category><![CDATA[SignBSL]]></category><category><![CDATA[Year in Review]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Wed, 15 Jan 2025 16:59:00 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2025/02/1000030579.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2025/02/1000030579.png" alt="Sign BSL Year Review 2024"><p>Greetings, British Sign Language enthusiasts!</p><p>We&apos;re excited to share an incredible milestone in our journey to promote and support sign language learning. As we reflect on the year 2024, we&#x2019;re thrilled to report some fascinating insights and achievements from www.signbsl.com.</p><p><strong>Record-Breaking Searches: </strong>In 2024, our website experienced a significant surge in activity, with <strong>536,288 unique visitors</strong> and a staggering <strong>29,957,642 searches</strong> made. This is a <strong>21.9% increase</strong> compared to the 24,587,983 searches in 2023. We are beyond grateful for the growing interest and engagement from our dedicated users worldwide.</p><p><strong>Top 50 Searched Words: </strong>Our users&#x2019; curiosity and dedication to learning have highlighted some intriguing trends in search activity. Here are the top 50 words searched on our site in 2024:</p><ol><li>how are you</li><li>dictionary</li><li>i love you</li><li>want</li><li>more</li><li>how</li><li>like</li><li>with</li><li>what</li><li>happy</li><li>when</li><li>thank you</li><li>no</li><li>good morning</li><li>why</li><li>do</li><li>toilet</li><li>and</li><li>have</li><li>love</li><li>tired</li><li>go</li><li>where</li><li>water</li><li>translator</li><li>my name is</li><li>holiday</li><li>favourite</li><li>help</li><li>can</li><li>school</li><li>need</li><li>today</li><li>you&apos;re welcome</li><li>hello</li><li>sorry</li><li>sign</li><li>beautiful</li><li>please</li><li>who</li><li>friend</li><li>dog</li><li>to</li><li>you</li><li>play</li><li>i</li><li>week</li><li>tomorrow</li><li>yes</li><li>work</li></ol><p>These searches reflect the essential and heartfelt expressions that bind us together in communication. Whether it&#x2019;s a simple greeting like &#x201C;how are you&#x201D; or expressing love with &#x201C;i love you,&#x201D; our users are learning to connect, share, and understand through the beautiful language of signs.</p><p><strong>Upgraded IOS BSL App: </strong>2024 also saw the release of our upgraded IOS BSL app, packed with user-friendly features to enhance your learning experience:</p><ul><li>New tabbed interface</li><li>Recent and Popular signs</li><li>Hide video controls overlay</li><li>Loop video playback</li><li>Add back and forward buttons to video player for quick access to alternative signs</li><li>Don&#x2019;t stop audio playback from other apps when playing videos</li><li>Show video attribution</li><li>Favourites</li><li>View your favourites offline</li><li>Dark mode support</li><li>Improved app start-up behaviour for offline access</li></ul><p>A big thank you to Mat Gadd for these fantastic updates that make our app more intuitive and enjoyable to use.</p><p><strong>Looking Ahead: </strong>As we look to 2025, our goal is to continue growing and enhancing our platform. We have exciting plans to introduce new features, expand our dictionary, and provide more educational resources to support our users&#x2019; learning journeys.</p><p>Thank you for being a part of our community and for your support.</p><p>Here&#x2019;s to another year of learning, growing, and connecting!</p>]]></content:encoded></item><item><title><![CDATA[Identifying Valid MX Records to Clean Up Your Mailing List]]></title><description><![CDATA[<p>When managing a mailing list, one critical task is ensuring that the email addresses in your list are valid. Sending emails to invalid addresses not only clutters your system but also harms your sender reputation, which can affect your email deliverability. One effective way to validate email addresses is by</p>]]></description><link>https://www.daniel-mitchell.com/blog/identifying-valid-mx-records-to-clean-up-your-mailing-list/</link><guid isPermaLink="false">67337f3c22fd18542d8b2c70</guid><category><![CDATA[Email]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Tue, 12 Nov 2024 16:25:27 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2024/11/Designer.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2024/11/Designer.png" alt="Identifying Valid MX Records to Clean Up Your Mailing List"><p>When managing a mailing list, one critical task is ensuring that the email addresses in your list are valid. Sending emails to invalid addresses not only clutters your system but also harms your sender reputation, which can affect your email deliverability. One effective way to validate email addresses is by checking their Mail Exchanger (MX) records.</p><h3 id="what-are-mx-records">What Are MX Records?</h3><p>MX records are a type of Domain Name System (DNS) record that specifies the mail servers responsible for receiving email on behalf of a domain. If a domain has valid MX records, it means it is configured to receive emails. An email address without a valid MX record is considered invalid for sending emails.</p><h3 id="why-check-mx-records">Why Check MX Records?</h3><ol><li><strong>Reduce Bounce Rates</strong>: Emails sent to addresses without valid MX records will bounce back. High bounce rates can negatively impact your sender reputation with email service providers.</li><li><strong>Improve Deliverability</strong>: Cleaning up your list by removing emails without valid MX records helps ensure that your messages reach the intended recipients, improving overall deliverability rates.</li><li><strong>Cost Efficiency</strong>: Sending emails to invalid addresses wastes resources. By identifying and removing these addresses, you can save on costs associated with email sending services.</li><li><strong>Enhanced Analytics</strong>: A cleaner list provides more accurate metrics and insights. Knowing that your emails are reaching valid addresses helps you better measure the success of your email campaigns.</li></ol><h2 id="bash-script">Bash Script</h2><p>To help you can use the Bash script below to check if a domain list has valid MX records. If there is no MX record then any email sent here will be bounced. This can be used to remove email addresses that are not valid.</p><p>File domains.txt:</p><pre><code class="language-bash">freebsd.org
redhat.com
yahoo.com
google.com</code></pre><p>Then create <code>mxlookup.sh</code></p><pre><code class="language-bash">output=&apos;ns_output.txt&apos;

# Clears previous output
&gt; $output

# Seconds to wait between lookups:
loop_wait=&apos;1&apos; # Is set to 1 second.

for domain in `cat $domain_list` # Start looping through domains
  do
    MX=$(dig MX $domain +short) #query MX records from domain list and store it as variable $MX
    #echo $MX &gt;&gt; $output;
    #echo $domain &gt;&gt; $output;
    arr=( $MX ) #creates array variable for the MX record answers
    echo ${domain} -- ${arr[1]} &gt;&gt; $output; #outputs only one record from above MX dig

    : &apos;
    for ((i=1; i&lt;${#arr[@]}; i+=2)); #since MX records have multiple answers, for loop goes through each answer
      do
        #echo $domain &gt;&gt; $output;
        echo ${arr[i]} &gt;&gt; $output; #outputs each A record from above MX dig
        #dig A +short &quot;${arr[i]}&quot; &gt;&gt; $output #queries A record for IP and writes answer
      done
    &apos;

  done;</code></pre><p>Run it <code>./mxlookup.sh</code> which will produce a file <code>ns_output.txt</code> which will allow you to identify domains without a valid MX record. These can then be removed from your mailer list.</p><h2 id="python-script">Python Script</h2><p>Or if you prefer you can use this python script:</p><pre><code class="language-python">import dns.resolver

def check_mx(domain):
    try:
        records = dns.resolver.resolve(domain, &apos;MX&apos;)
        return True
    except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
        return False

domains = [&quot;example.com&quot;, &quot;invalid-domain.com&quot;]
valid_domains = [domain for domain in domains if check_mx(domain)]
print(f&quot;Valid domains: {valid_domains}&quot;)</code></pre><p>By regularly checking the MX records of the domains in your mailing list, you can maintain a clean and efficient list, improve your email deliverability, and protect your sending reputation.</p>]]></content:encoded></item><item><title><![CDATA[Send email with AWS SES in a CloudFlare Worker]]></title><description><![CDATA[<p>To send an email via a CloudFlare Worker you will need to call a email provider. AWS Simple Email Service (SES) is a robust transactional email provider that I already use in a number of other projects, and simplifies my billing. However the JavaScript SDK provided by AWS is very</p>]]></description><link>https://www.daniel-mitchell.com/blog/send-email-with-aws-ses-in-a-cloudflare-workers/</link><guid isPermaLink="false">666ca472594dd90d996ef9b6</guid><category><![CDATA[Email]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Mon, 01 Jul 2024 16:13:07 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2024/07/Cloudflare-and-SES.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2024/07/Cloudflare-and-SES.png" alt="Send email with AWS SES in a CloudFlare Worker"><p>To send an email via a CloudFlare Worker you will need to call a email provider. AWS Simple Email Service (SES) is a robust transactional email provider that I already use in a number of other projects, and simplifies my billing. However the JavaScript SDK provided by AWS is very large and is not compatible with the CloudFlare Worker runtime. So we will want to roll our own simple API call to the SES.</p><h2 id="prerequisites-and-setup">Prerequisites and Setup</h2><ul><li>Setup the domain identity in SES. This will require you to add 3 CNAME records to your domain name.</li><li>You can then create a new IAM user with an IAM Inline Policy to restrict access to a particular email address.</li></ul><!--kg-card-begin: markdown--><pre><code>{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Action&quot;: [
                &quot;ses:SendEmail&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;,
            &quot;Condition&quot;: {
                &quot;StringEquals&quot;: {
                    &quot;ses:FromAddress&quot;: &quot;help@fiftypencedirectdebit.co.uk&quot;
                }
            }
        }
    ]
}
</code></pre>
<!--kg-card-end: markdown--><ul><li>You will need to create access key for this new user, which will provide the credentials you will use in the code.</li><li>For the contact sending we will use code from the <a href="https://github.com/mhart/aws4fetch">AWS 4 Fetch</a> project on GitHub - This project will handle the authentication required to use SES.</li></ul><!--kg-card-begin: markdown--><p><code>npm install aws4fetch</code></p>
<!--kg-card-end: markdown--><ul><li>Below is the code I am using. (Remember to change your <a href="https://docs.aws.amazon.com/general/latest/gr/ses.html">SES region</a>). </li></ul><!--kg-card-begin: markdown--><pre><code>export async function sendEmail(toEmail, subjectLine, message) {
	const aws = new AwsClient({ accessKeyId: IAM_ACCESS_KEY, secretAccessKey: IAM_ACCESS_KEY_SECRET&apos; });
	let resp = await aws.fetch(&apos;https://email.eu-west-1.amazonaws.com/v2/email/outbound-emails&apos;, {
		method: &apos;POST&apos;,
		headers: {
			&apos;content-type&apos;: &apos;application/json&apos;,
		},
		body: JSON.stringify({
			Destination: 
			{
				ToAddresses: [ toEmail ],
				BccAddresses: [ &apos;me@daniel-mitchell.com&apos; ],
			},
			FromEmailAddress: &apos;Fifty Pence Direct Debit &lt;help@fiftypencedirectdebit.co.uk&gt;&apos;,
			Content: {
				Simple: {
					Subject: {
						Data: subjectLine
					},
					Body: {
						Text: {
							Data: message.replace(/&lt;br\s*[\/]?&gt;/gi, &quot;\n&quot;),
						},
						Html: {
							Data: &apos;&lt;body&gt;&lt;div align=&quot;center&quot; style=&quot;font-family:Calibri, Arial, Helvetica, sans-serif;&quot;&gt;&lt;table width=&quot;600&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; border=&quot;0&quot; style=&quot;font-family:Calibri, Arial, Helvetica, sans-serif&quot;&gt;&lt;tr style=&quot;background-color:white;&quot;&gt;&lt;td&gt;&lt;table width=&quot;600&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;&lt;td&gt;&lt;h1&gt;Fifty Pence Direct Debit&lt;/h1&gt;&lt;p&gt;&apos; + message +&apos;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/body&gt;&apos;,
						}
					}
				},
			},
		}),
	});

	const respText = await resp.json();
	console.log(resp.status + &quot; &quot; + resp.statusText);
	console.log(respText);
	if (resp.status != 200 &amp;&amp; resp.status != 201) {
		throw new Error(&apos;Error sending email: &apos; + resp.status + &quot; &quot; + resp.statusText + &quot; &quot; + respText);
	}
	return resp.status;
}
</code></pre>
<!--kg-card-end: markdown--><ul><li>Send the email via a function call:</li></ul><!--kg-card-begin: markdown--><p><code>ctx.waitUntil(sendEmail(&apos;Email To Address&apos;, &apos;Subject Line&apos;, &apos;Html Message here&apos;));</code></p>
<!--kg-card-end: markdown--><p>The SES parameters that can be used in the API call can be found in the AWS documentation: <a href="https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_SendEmail.html">https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_SendEmail.html</a></p>]]></content:encoded></item><item><title><![CDATA[Unlocking Bank Switch Bonuses with Fifty Pence Direct Debit]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Switching banks has never been more rewarding. With enticing cash bonuses, interest rates, and other perks, savvy consumers are capitalizing on these offers. However, many of these deals come with a requirement: you need to have active direct debits. But what if you could set up these direct debits without</p>]]></description><link>https://www.daniel-mitchell.com/blog/unlocking-bank-switch-bonuses-with-fifty-pence-direct-debit/</link><guid isPermaLink="false">666364be594dd90d996ef95e</guid><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Mon, 10 Jun 2024 11:06:00 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2024/06/blog-fifty-pence.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://www.daniel-mitchell.com/content/images/2024/06/blog-fifty-pence.png" alt="Unlocking Bank Switch Bonuses with Fifty Pence Direct Debit"><p>Switching banks has never been more rewarding. With enticing cash bonuses, interest rates, and other perks, savvy consumers are capitalizing on these offers. However, many of these deals come with a requirement: you need to have active direct debits. But what if you could set up these direct debits without breaking the bank? Enter <strong>Fifty Pence Direct Debit</strong>, the service that makes it easy for you to manage your direct debits for just 50p per transaction.</p>
<p><strong>What Is Fifty Pence Direct Debit?</strong></p>
<p>Fifty Pence Direct Debit is a simple service to help those looking to take advantage of bank switch offers. Here&apos;s why:</p>
<ol>
<li>
<p><strong>Affordability</strong>: For only 50p per direct debit, it is the cheapest service to set up hassle-free direct debits for bank switching.</p>
</li>
<li>
<p><strong>Speedy Setup</strong>: Need to switch banks quickly? Fifty Pence Direct Debit has you covered. Their simple signup ensures that you&apos;re up and running in no time. New direct debits are setup in 5 working days.</p>
</li>
<li>
<p><strong>Flexible Usage</strong>: Whether you need one, two direct debits or more, Fifty Pence Direct Debit has got you covered. You can use the same service multiple times if necessary.</p>
</li>
</ol>
<p><strong>How It Works</strong></p>
<ol>
<li>
<p><strong>Sign Up</strong>: Visit the <a href="https://www.50pdirectdebit.co.uk/">50p Direct Debit</a> website and sign up. Provide your basic details, and you&apos;re ready to roll.</p>
</li>
<li>
<p><strong>Pay Only 50p</strong>: Each direct debit setup costs just 50p. It&apos;s a small price to pay for the convenience and savings you&apos;ll enjoy.</p>
</li>
</ol>
<p><strong>Security and Peace of Mind</strong></p>
<p>Fifty Pence Direct Debit takes security seriously. Here&apos;s why you can trust them:</p>
<ul>
<li>
<p><strong>Payment Gateway</strong>: All payment processing is handled by the reputable payment gateway, <strong>Stripe</strong>. Your financial information is encrypted and secure.</p>
</li>
<li>
<p><strong>Cancellation Flexibility</strong>: Once your bank switch is complete, you have options. You can cancel the direct debit payment from your banking mobile app or leave it running for your next switch. It&apos;s entirely up to you.</p>
</li>
</ul>
<p><strong>Maximizing Bank Switch Offers</strong></p>
<p>Now that you&apos;ve set up your affordable direct debits with Fifty Pence Direct Debit, here are some recent of bank switch offers:</p>
<ol>
<li><strong>Santander</strong>: Get a FREE &#xA3;175 cash bonus plus 1% cashback when you switch to Santander.</li>
<li><strong>First Direct</strong>: Enjoy a FREE &#xA3;175 bonus along with top-notch service.</li>
<li><strong>TSB</strong>: Grab a FREE &#xA3;100 bonus plus an additional &#xA3;60 over 6 months.</li>
<li><strong>Virgin Money</strong>: Benefit from 12.68% interest for the first 12 months.</li>
<li><strong>Nationwide</strong>: Existing customers can earn a FREE &#xA3;200 bonus.</li>
</ol>
<p>Remember, these offers change over time, so always check the latest deals. With Fifty Pence Direct Debit, you&apos;re well on your way to maximizing your rewards without breaking the bank.</p>
<p><strong>Conclusion</strong></p>
<p><a href="https://www.50pdirectdebit.co.uk/">50p Direct Debit</a> is your secret weapon for hassle-free direct debits. Switch banks, unlock bonuses, and keep more money in your pocket &#x2013; all for just 50p!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[The Real Cost of Free Transactional Email Services]]></title><description><![CDATA[<p>When it comes to managing costs, especially ongoing ones, businesses and individuals with side projects alike seek efficient solutions. Email services are no exception. While free email providers can be enticing initially, they come with a serious drawback. Learn from my experience that see that resisting the draw of free</p>]]></description><link>https://www.daniel-mitchell.com/blog/the-real-cost-of-free-transactional-email-services/</link><guid isPermaLink="false">66622cbe594dd90d996ef8a5</guid><category><![CDATA[Email]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Fri, 07 Jun 2024 19:50:10 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2024/06/blog-email-header.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2024/06/blog-email-header.png" alt="The Real Cost of Free Transactional Email Services"><p>When it comes to managing costs, especially ongoing ones, businesses and individuals with side projects alike seek efficient solutions. Email services are no exception. While free email providers can be enticing initially, they come with a serious drawback. Learn from my experience that see that resisting the draw of free email services and opting for paid transactional email services from the beginning is the smart choice.</p><p><strong><strong>The Free Service Dilemma:</strong></strong></p><ul><li>Free email services are convenient when setting up a project. They run smoothly for months or even years without any cost.</li><li>However, there&#x2019;s a catch: these free services eventually get discontinued. The abrupt announcement of it being discontinued can seriously disrupt your workflow, especially if you haven&#x2019;t revisited the project in a while.</li></ul><p><strong><strong>The Hidden Costs of Free Services:</strong></strong></p><p>When a free service is pulled, you&#x2019;re left scrambling to:</p><ul><li>Retrieve the project details.</li><li>Understand the deployment process.</li><li>Perform necessary upgrades.</li><li>Find, evaluate and transition to the new provider.</li><li>Update DNS entries.</li><li>Test and deploy.</li></ul><p>These tasks consume valuable time and will completely negate any savings from using a free service that seems like such a good idea at the start.</p><p><strong><strong>The Solution: </strong>Always opt for paid transactional email services<strong>:</strong></strong></p><p>Here&#x2019;s why:</p><ul><li><strong>Minimal Cost:</strong> The expense of using a paid service is negligible compared to the time and stress saved when the service is inevitably pulled<strong>.</strong></li></ul><p><strong><strong>Personal Experience:</strong></strong></p><p>I have made the mistake of using a free email service twice:</p><ul><li>Once with MailChimp, which initially provided 5,000 free emails per month. Unfortunately, it was discontinued with just 30 days&#x2019; notice, prompting my move to AWS for my email needs.</li><li>MailChannels in conjunction with CloudFlare Workers allowed unlimited free emails, but again they pulled the service abruptly. They even started immediately failing a small percentage of emails without any grace period, impacting my service. Again, I had to scramble to switch provider.</li></ul><blockquote>While I choose AWS because that is what I am already familiar with, any reputable email service provider will suffice. The important thing is to ensure that the service has long term support and will not leave you in the lurch by pulling the API or service.</blockquote><p>In summary, investing in paid transactional email services ensures stability, peace of mind, and efficient workflows. The minimal cost is well worth the long-term benefits.</p>]]></content:encoded></item><item><title><![CDATA[SignASL year in review 2023]]></title><description><![CDATA[<p>In 2023 <strong>32,197,037</strong> searches were made on www.signasl.org a massive <strong>+22.5%</strong> increase from last year! (This is a 31% higher search volume compared to Sign BSL). Below I have provided a snapshot of the top 50 most searched words during the year.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Search Query</th>
<th style="text-align:right">No.</th></tr></thead></table>]]></description><link>https://www.daniel-mitchell.com/blog/signasl-year-in-review-2023/</link><guid isPermaLink="false">6593eeff509eab04a30d4679</guid><category><![CDATA[SignASL]]></category><category><![CDATA[Sign Language]]></category><category><![CDATA[Year in Review]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Tue, 02 Jan 2024 16:21:14 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2024/01/Adobe_Express_20231225_2356100_1-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2024/01/Adobe_Express_20231225_2356100_1-1.png" alt="SignASL year in review 2023"><p>In 2023 <strong>32,197,037</strong> searches were made on www.signasl.org a massive <strong>+22.5%</strong> increase from last year! (This is a 31% higher search volume compared to Sign BSL). Below I have provided a snapshot of the top 50 most searched words during the year.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Search Query</th>
<th style="text-align:right">No. searches</th>
<th style="text-align:right">% change</th>
</tr>
</thead>
<tbody>
<tr>
<td>****</td>
<td style="text-align:right">62,356</td>
<td style="text-align:right">96%</td>
</tr>
<tr>
<td>****</td>
<td style="text-align:right">45,408</td>
<td style="text-align:right">109%</td>
</tr>
<tr>
<td>abortion</td>
<td style="text-align:right">37,692</td>
<td style="text-align:right">758%</td>
</tr>
<tr>
<td>you&apos;re welcome</td>
<td style="text-align:right">35,950</td>
<td style="text-align:right">225%</td>
</tr>
<tr>
<td>****</td>
<td style="text-align:right">30,649</td>
<td style="text-align:right">9%</td>
</tr>
<tr>
<td>****</td>
<td style="text-align:right">26,458</td>
<td style="text-align:right">109%</td>
</tr>
<tr>
<td>****</td>
<td style="text-align:right">26,199</td>
<td style="text-align:right">47%</td>
</tr>
<tr>
<td>****</td>
<td style="text-align:right">25,883</td>
<td style="text-align:right">52%</td>
</tr>
<tr>
<td>****</td>
<td style="text-align:right">23,845</td>
<td style="text-align:right">163%</td>
</tr>
<tr>
<td>translate</td>
<td style="text-align:right">23,161</td>
<td style="text-align:right">337%</td>
</tr>
<tr>
<td>have</td>
<td style="text-align:right">19,699</td>
<td style="text-align:right">35%</td>
</tr>
<tr>
<td>good</td>
<td style="text-align:right">19,636</td>
<td style="text-align:right">34%</td>
</tr>
<tr>
<td>what</td>
<td style="text-align:right">19,063</td>
<td style="text-align:right">34%</td>
</tr>
<tr>
<td>like</td>
<td style="text-align:right">18,955</td>
<td style="text-align:right">34%</td>
</tr>
<tr>
<td>love</td>
<td style="text-align:right">18,746</td>
<td style="text-align:right">50%</td>
</tr>
<tr>
<td>want</td>
<td style="text-align:right">18,742</td>
<td style="text-align:right">48%</td>
</tr>
<tr>
<td>how</td>
<td style="text-align:right">18,425</td>
<td style="text-align:right">31%</td>
</tr>
<tr>
<td>when</td>
<td style="text-align:right">18,030</td>
<td style="text-align:right">33%</td>
</tr>
<tr>
<td>thank you</td>
<td style="text-align:right">17,029</td>
<td style="text-align:right">40%</td>
</tr>
<tr>
<td>how are you</td>
<td style="text-align:right">17,005</td>
<td style="text-align:right">52%</td>
</tr>
<tr>
<td>to</td>
<td style="text-align:right">16,915</td>
<td style="text-align:right">53%</td>
</tr>
<tr>
<td>and</td>
<td style="text-align:right">16,487</td>
<td style="text-align:right">39%</td>
</tr>
<tr>
<td>do</td>
<td style="text-align:right">15,786</td>
<td style="text-align:right">34%</td>
</tr>
<tr>
<td>is</td>
<td style="text-align:right">15,754</td>
<td style="text-align:right">31%</td>
</tr>
<tr>
<td>with</td>
<td style="text-align:right">15,131</td>
<td style="text-align:right">30%</td>
</tr>
<tr>
<td>school</td>
<td style="text-align:right">14,970</td>
<td style="text-align:right">35%</td>
</tr>
<tr>
<td>where</td>
<td style="text-align:right">14,846</td>
<td style="text-align:right">28%</td>
</tr>
<tr>
<td>hello</td>
<td style="text-align:right">14,788</td>
<td style="text-align:right">28%</td>
</tr>
<tr>
<td>happy</td>
<td style="text-align:right">14,765</td>
<td style="text-align:right">29%</td>
</tr>
<tr>
<td>i</td>
<td style="text-align:right">14,516</td>
<td style="text-align:right">32%</td>
</tr>
<tr>
<td>for</td>
<td style="text-align:right">14,456</td>
<td style="text-align:right">58%</td>
</tr>
<tr>
<td>why</td>
<td style="text-align:right">14,440</td>
<td style="text-align:right">41%</td>
</tr>
<tr>
<td>we</td>
<td style="text-align:right">14,243</td>
<td style="text-align:right">52%</td>
</tr>
<tr>
<td>go</td>
<td style="text-align:right">14,233</td>
<td style="text-align:right">31%</td>
</tr>
<tr>
<td>you</td>
<td style="text-align:right">14,225</td>
<td style="text-align:right">60%</td>
</tr>
<tr>
<td>dog</td>
<td style="text-align:right">14,164</td>
<td style="text-align:right">44%</td>
</tr>
<tr>
<td>help</td>
<td style="text-align:right">14,030</td>
<td style="text-align:right">44%</td>
</tr>
<tr>
<td>need</td>
<td style="text-align:right">13,927</td>
<td style="text-align:right">35%</td>
</tr>
<tr>
<td>the</td>
<td style="text-align:right">13,435</td>
<td style="text-align:right">68%</td>
</tr>
<tr>
<td>no</td>
<td style="text-align:right">13,418</td>
<td style="text-align:right">44%</td>
</tr>
<tr>
<td>no more</td>
<td style="text-align:right">13,412</td>
<td style="text-align:right">27%</td>
</tr>
<tr>
<td>favorite</td>
<td style="text-align:right">13,337</td>
<td style="text-align:right">14%</td>
</tr>
<tr>
<td>play</td>
<td style="text-align:right">13,247</td>
<td style="text-align:right">42%</td>
</tr>
<tr>
<td>peace</td>
<td style="text-align:right">12,938</td>
<td style="text-align:right">4%</td>
</tr>
<tr>
<td>please</td>
<td style="text-align:right">12,913</td>
<td style="text-align:right">37%</td>
</tr>
<tr>
<td>glory</td>
<td style="text-align:right">12,862</td>
<td style="text-align:right">33%</td>
</tr>
<tr>
<td>not</td>
<td style="text-align:right">12,732</td>
<td style="text-align:right">52%</td>
</tr>
<tr>
<td>can</td>
<td style="text-align:right">12,615</td>
<td style="text-align:right">22%</td>
</tr>
<tr>
<td>in</td>
<td style="text-align:right">12,557</td>
<td style="text-align:right">34%</td>
</tr>
<tr>
<td>know</td>
<td style="text-align:right">12,539</td>
<td style="text-align:right">54%</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Offensive language and racial slurs<strong> </strong>continue to see a significant increase in searches, with 7 of the top 10 most searched queries containing offensive terms, this is intriguing compared to the search data from the BSL version of the site where the top 50 searches do not contain any such offensive terms.</p><p>The big stand out search query for 2023 is searches for &quot;abortion&quot; which experienced a 758% increase from 2022, making it the 3rd most commonly searched word. This is not surprising given the political situation in the United States in 2023.</p><p>Aside from the offensive language, common and neutral terms such as &quot;translate,&quot; &quot;have,&quot; &quot;good,&quot; &quot;what,&quot; and &quot;like&quot; have also seen increases in searches, suggesting a diverse range of user interests and language learning activities. Polite expressions like &quot;you&apos;re welcome,&quot; &quot;thank you,&quot; and &quot;please&quot; have high search volumes, indicating a focus on communication etiquette.</p><p>Basic language components such as pronouns (&quot;I,&quot; &quot;you,&quot; &quot;we&quot;), conjunctions (&quot;and,&quot; &quot;or,&quot; &quot;with&quot;), and prepositions (&quot;to,&quot; &quot;for,&quot; &quot;in&quot;) are frequently searched, reflecting a typical pattern of language learning.</p><p>Question words like &quot;how,&quot; &quot;when,&quot; &quot;where,&quot; and &quot;why&quot; are commonly searched, suggesting users are interested in learning how to frame questions. Positive expressions like &quot;love,&quot; &quot;happy,&quot; and &quot;peace&quot; are searched frequently, indicating a desire for positive and uplifting conversations.</p><p><strong>Other news updates</strong></p><p>An update to the <a href="https://play.google.com/store/apps/details?id=com.signasl.signasl">SignASL android app</a> was released to fix video playback issues and support the latest versions of Android. (Special thanks to <a href="https://twitter.com/thegazler">Gary Rennie</a> for your support with this app.)</p><p>I would also like to thank <a href="https://twitter.com/zpakrueger">Zachary Krueger</a> a Sign Language Interpreter from Iowa who has for the last few months been reviewing and improving the quality of the ASL dictionary (removing incorrect signs and fixing the word definition associations for the videos).</p><p>For those interested in the technology stack that powers the ASL dictionary, I have upgraded the MySQL database from 5.7 to version 8. I have also upgraded the AWS Lambda functions from dot net core 3.1 to .net6. I have also replaced most YouTube embeds to use self hosted videos for improved playback experience.</p><p>Looking forward to what 2024 will bring for SignASL!</p>]]></content:encoded></item><item><title><![CDATA[SignBSL year in review 2023]]></title><description><![CDATA[<p>In 2023 <strong>24,587,983</strong> searches were made on www.signbsl.com a <strong>+4.2%</strong> increase from last year indicating a growing interest in BSL which I expect to continue, especially with the plans to allow students to learn BSL as a GCSE subject. Below I have provided a snapshot</p>]]></description><link>https://www.daniel-mitchell.com/blog/signbsl-year-in-review-2023/</link><guid isPermaLink="false">65933943509eab04a30d45ed</guid><category><![CDATA[SignBSL]]></category><category><![CDATA[Sign Language]]></category><category><![CDATA[Year in Review]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Mon, 01 Jan 2024 22:48:28 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2024/01/Adobe_Express_20231225_2356100_1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2024/01/Adobe_Express_20231225_2356100_1.png" alt="SignBSL year in review 2023"><p>In 2023 <strong>24,587,983</strong> searches were made on www.signbsl.com a <strong>+4.2%</strong> increase from last year indicating a growing interest in BSL which I expect to continue, especially with the plans to allow students to learn BSL as a GCSE subject. Below I have provided a snapshot of the top 50 most searched words.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Search Query</th>
<th style="text-align:right">No. Searches</th>
<th style="text-align:right">% change from last year</th>
</tr>
</thead>
<tbody>
<tr>
<td>how are you</td>
<td style="text-align:right">45,364</td>
<td style="text-align:right">-1%</td>
</tr>
<tr>
<td>i love you</td>
<td style="text-align:right">43,547</td>
<td style="text-align:right">2%</td>
</tr>
<tr>
<td>want</td>
<td style="text-align:right">33,111</td>
<td style="text-align:right">7%</td>
</tr>
<tr>
<td>with</td>
<td style="text-align:right">31,836</td>
<td style="text-align:right">24%</td>
</tr>
<tr>
<td>how</td>
<td style="text-align:right">30,632</td>
<td style="text-align:right">11%</td>
</tr>
<tr>
<td>thank you</td>
<td style="text-align:right">28,823</td>
<td style="text-align:right">16%</td>
</tr>
<tr>
<td>more</td>
<td style="text-align:right">28,680</td>
<td style="text-align:right">22%</td>
</tr>
<tr>
<td>what</td>
<td style="text-align:right">28,063</td>
<td style="text-align:right">8%</td>
</tr>
<tr>
<td>happy</td>
<td style="text-align:right">27,450</td>
<td style="text-align:right">9%</td>
</tr>
<tr>
<td>good morning</td>
<td style="text-align:right">27,415</td>
<td style="text-align:right">2%</td>
</tr>
<tr>
<td>dictionary</td>
<td style="text-align:right">27,321</td>
<td style="text-align:right">43%</td>
</tr>
<tr>
<td>no</td>
<td style="text-align:right">25,227</td>
<td style="text-align:right">12%</td>
</tr>
<tr>
<td>like</td>
<td style="text-align:right">24,657</td>
<td style="text-align:right">10%</td>
</tr>
<tr>
<td>when</td>
<td style="text-align:right">24,192</td>
<td style="text-align:right">3%</td>
</tr>
<tr>
<td>why</td>
<td style="text-align:right">23,762</td>
<td style="text-align:right">4%</td>
</tr>
<tr>
<td>hello</td>
<td style="text-align:right">23,434</td>
<td style="text-align:right">-1%</td>
</tr>
<tr>
<td>you&apos;re welcome</td>
<td style="text-align:right">23,089</td>
<td style="text-align:right">21%</td>
</tr>
<tr>
<td>my name is</td>
<td style="text-align:right">22,542</td>
<td style="text-align:right">-8%</td>
</tr>
<tr>
<td>and</td>
<td style="text-align:right">21,812</td>
<td style="text-align:right">15%</td>
</tr>
<tr>
<td>have</td>
<td style="text-align:right">21,683</td>
<td style="text-align:right">11%</td>
</tr>
<tr>
<td>do</td>
<td style="text-align:right">21,555</td>
<td style="text-align:right">18%</td>
</tr>
<tr>
<td>toilet</td>
<td style="text-align:right">21,353</td>
<td style="text-align:right">11%</td>
</tr>
<tr>
<td>tired</td>
<td style="text-align:right">21,061</td>
<td style="text-align:right">10%</td>
</tr>
<tr>
<td>love</td>
<td style="text-align:right">20,475</td>
<td style="text-align:right">11%</td>
</tr>
<tr>
<td>where</td>
<td style="text-align:right">20,135</td>
<td style="text-align:right">9%</td>
</tr>
<tr>
<td>sorry</td>
<td style="text-align:right">19,503</td>
<td style="text-align:right">19%</td>
</tr>
<tr>
<td>today</td>
<td style="text-align:right">19,293</td>
<td style="text-align:right">10%</td>
</tr>
<tr>
<td>go</td>
<td style="text-align:right">19,114</td>
<td style="text-align:right">14%</td>
</tr>
<tr>
<td>please</td>
<td style="text-align:right">18,935</td>
<td style="text-align:right">16%</td>
</tr>
<tr>
<td>school</td>
<td style="text-align:right">18,512</td>
<td style="text-align:right">12%</td>
</tr>
<tr>
<td>water</td>
<td style="text-align:right">18,371</td>
<td style="text-align:right">9%</td>
</tr>
<tr>
<td>dog</td>
<td style="text-align:right">18,286</td>
<td style="text-align:right">16%</td>
</tr>
<tr>
<td>beautiful</td>
<td style="text-align:right">18,249</td>
<td style="text-align:right">12%</td>
</tr>
<tr>
<td>can</td>
<td style="text-align:right">17,958</td>
<td style="text-align:right">15%</td>
</tr>
<tr>
<td>help</td>
<td style="text-align:right">17,673</td>
<td style="text-align:right">14%</td>
</tr>
<tr>
<td>i</td>
<td style="text-align:right">17,520</td>
<td style="text-align:right">17%</td>
</tr>
<tr>
<td>sign</td>
<td style="text-align:right">17,374</td>
<td style="text-align:right">32%</td>
</tr>
<tr>
<td>who</td>
<td style="text-align:right">17,309</td>
<td style="text-align:right">10%</td>
</tr>
<tr>
<td>favourite</td>
<td style="text-align:right">17,140</td>
<td style="text-align:right">22%</td>
</tr>
<tr>
<td>you</td>
<td style="text-align:right">17,025</td>
<td style="text-align:right">15%</td>
</tr>
<tr>
<td>need</td>
<td style="text-align:right">16,937</td>
<td style="text-align:right">13%</td>
</tr>
<tr>
<td>boy</td>
<td style="text-align:right">16,869</td>
<td style="text-align:right">32%</td>
</tr>
<tr>
<td>yes</td>
<td style="text-align:right">16,850</td>
<td style="text-align:right">9%</td>
</tr>
<tr>
<td>holiday</td>
<td style="text-align:right">16,835</td>
<td style="text-align:right">5%</td>
</tr>
<tr>
<td>friend</td>
<td style="text-align:right">16,665</td>
<td style="text-align:right">12%</td>
</tr>
<tr>
<td>girl</td>
<td style="text-align:right">16,378</td>
<td style="text-align:right">21%</td>
</tr>
<tr>
<td>tomorrow</td>
<td style="text-align:right">15,823</td>
<td style="text-align:right">10%</td>
</tr>
<tr>
<td>good</td>
<td style="text-align:right">15,541</td>
<td style="text-align:right">5%</td>
</tr>
<tr>
<td>translator</td>
<td style="text-align:right">15,295</td>
<td style="text-align:right">28%</td>
</tr>
<tr>
<td>to</td>
<td style="text-align:right">15,230</td>
<td style="text-align:right">21%</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Its pleasing to see that the common themes of the top searches include: Basic communication phrases, expressions of love and affection, inquiries about well-being, and seeking information. There is a strong interest in everyday communication. The top searches highlight the importance of BSL for everyday interactions and relationship building.</p><p><strong>Other news updates</strong></p><p>An update to the <a href="https://play.google.com/store/apps/details?id=com.signbsl.signbsl">SignBSL android app</a> was also released to fix video playback issues and support the latest versions of Android. (Special thanks to <a href="https://twitter.com/thegazler">Gary Rennie</a> for your support with this app.)</p><p>In preparation for the new GSCE in BSL I have added a new page to make it easy to find all the <a href="https://www.signbsl.com/gcse-vocabulary">BSL GCSE vocabulary</a> that students are expected to learn as part of their qualification.</p><p>For those who use Reddit, I have now setup daily auto posting of videos to the <a href="https://www.reddit.com/r/BSL/">BSL subreddit</a>. This posts the same videos as found on <a href="https://twitter.com/Bslsign">twitter</a>.</p><p>For those interested in the technology stack that powers the BSL dictionary, I have upgraded the MySQL database from 5.7 to version 8. I have also upgraded the AWS Lambda functions from dot net core 3.1 to .net6. I have also replaced most YouTube embeds to use self hosted videos for improved playback experience.</p><p>Looking forward to what 2024 will bring for SignBSL!</p>]]></content:encoded></item><item><title><![CDATA[Partitioned Cookies in C#]]></title><description><![CDATA[<p>As browsers start to phase out 3rd party cookies developers need to start using the <code>partitioned</code> cookie attribute (this is a new feature of <strong>C</strong>ookies <strong>H</strong>aving <strong>I</strong>ndependent <strong>P</strong>artitioned State <strong>C</strong>HIPS). This will allow users to login when accessing your site in an iframe whiles maintaining</p>]]></description><link>https://www.daniel-mitchell.com/blog/partitioned-cookies-in-c-sharp/</link><guid isPermaLink="false">65537a82b1529a3b88d21e93</guid><category><![CDATA[C#]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Tue, 14 Nov 2023 13:58:38 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2023/11/Untitled.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2023/11/Untitled.png" alt="Partitioned Cookies in C#"><p>As browsers start to phase out 3rd party cookies developers need to start using the <code>partitioned</code> cookie attribute (this is a new feature of <strong>C</strong>ookies <strong>H</strong>aving <strong>I</strong>ndependent <strong>P</strong>artitioned State <strong>C</strong>HIPS). This will allow users to login when accessing your site in an iframe whiles maintaining privacy. While blocking 3rd party cookies is not yet set as the default, all the major browsers are planning to do this. Also to support users using Chrome in incognito mode you need to be ready to support this, otherwise you will be prevented from setting a cookie.</p><p>The partitioned attribute is supported in Chrome 114 and higher, it is also supported by Edge. How it works is well explained at <a href="https://developer.chrome.com/docs/privacy-sandbox/chips/">https://developer.chrome.com/docs/privacy-sandbox/chips/</a> - essentially the cookie is partitioned according to the parent top level site. (See diagram below).</p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2023/11/image.png" class="kg-image" alt="Partitioned Cookies in C#" loading="lazy" width="845" height="468" srcset="https://www.daniel-mitchell.com/content/images/size/w600/2023/11/image.png 600w, https://www.daniel-mitchell.com/content/images/2023/11/image.png 845w" sizes="(min-width: 720px) 720px"></figure><p>To configure this you need to set the cookie header:</p><pre><code>Set-Cookie: __Host-name=value; Secure; Path=/; SameSite=None; Partitioned;</code></pre><p>C# does not yet have an option to appended this <code>Partitioned</code> attribute, but you can just append the <code>Partitioned</code> property to the Path option. For example:</p><pre><code class="language-c#">Response.Cookies.Append(&quot;X-Access-Token&quot;, accessToken, new CookieOptions()
{
    HttpOnly = true,
    Secure = true,
    SameSite = SameSiteMode.None,
    Path = &quot;/; samesite=None; Partitioned&quot;
});</code></pre><p>This code also includes a fix to ensure the option <code>samesite=None</code> is outputted into the cookie (which is also required for 3rd party cookies).</p>]]></content:encoded></item><item><title><![CDATA[Email Spam Headers]]></title><description><![CDATA[<p>One way to help reduce the chances of your emails being marked as spam is to understand email spam headers. Spam headers are the hidden messages that are attached to every email. They contain information about the sender, the recipient, and the content of the email.</p><p>Two of the most</p>]]></description><link>https://www.daniel-mitchell.com/blog/email-spam-headers/</link><guid isPermaLink="false">649c3d99497b6004bd58baf9</guid><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Wed, 28 Jun 2023 15:28:07 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1530436098968-cab21a5dfea6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDU2fHxlbWFpbCUyMHNwYW18ZW58MHx8fHwxNjg3OTY1OTc3fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1530436098968-cab21a5dfea6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDU2fHxlbWFpbCUyMHNwYW18ZW58MHx8fHwxNjg3OTY1OTc3fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Email Spam Headers"><p>One way to help reduce the chances of your emails being marked as spam is to understand email spam headers. Spam headers are the hidden messages that are attached to every email. They contain information about the sender, the recipient, and the content of the email.</p><p>Two of the most important spam headers are <strong>SPF </strong>and <strong>DKIM</strong>. SPF stands for Sender Policy Framework. It is a way for businesses to tell email servers which servers are authorized to send email on their behalf. DKIM stands for DomainKeys Identified Mail. It is a way for businesses to sign their email messages with a digital signature. This signature can be used to verify that the email message is actually from the sender it claims to be from.</p><h2 id="what-to-check">What to check</h2><ol><li><strong>SPF</strong></li></ol><p>SPF is a way for businesses to tell email servers which servers are authorized to send email on their behalf. This information is stored in a DNS record called the SPF record. The SPF record for a domain tells email servers which IP addresses are authorized to send email from that domain.</p><p>When an email server receives an email message, it will check the SPF record for the domain that the email message is from. If the IP address of the server that sent the email message is not listed in the SPF record, the email server will likely mark the email message as spam.</p><p>To check if this is setup correctly, in the message header you are looking for something that says:</p><p><code>Authentication-Results: spf=pass (sender IP is 159.135.225.169) smtp.mailfrom=daniel-mitchell.com;</code></p><p>If you can see <code>spf=pass</code> then this means the domain setup is correct. If not you will need to check the instructions provided by your email provider. They require a TXT DNS record that explains which IP addresses are allowed to send email on behalf of your domain.</p><p><strong>2. DKIM</strong></p><p>While not a requirement for email to be delivered to a users inbox it will increase its chances, and is well worth setting up correctly. The DKIM signature is created by the business that sends the email message. The signature is then included in the email message header. When an email server receives an email message, it will check the DKIM signature to verify that the email message is actually from the sender it claims to be from.</p><p>If the DKIM signature is valid, the email server will likely deliver the email message to the recipient&apos;s inbox. If the DKIM signature is invalid, the email server may mark the email message as spam or block it altogether.</p><p>To check if DKIM is setup correctly, in the message header you are looking for something that says:</p><p><code>dkim=pass (signature was verified)</code></p><p>If DKIM is not setup or the email is not signed, it will say:</p><p><code>dkim=none (message not signed)</code></p><p>To fix these issues you will need to check the instructions provided by your email provider. They require two CNAME DNS record that contain the DKIM signing key.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">&#x2139;&#xFE0F;</div><div class="kg-callout-text">DKIM is not automatically setup when you use Microsoft 365. Setup DKIM under Email Authentication Settings: https://security.microsoft.com/dkimv2</div></div><p><strong>3. Other SPAM headers</strong></p><p>This will vary according to the users email provider. They all have different rules and configuration. These headers are for users who use Microsoft365 for their email.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Header Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>X-MS-Exchange-Organization-PCL:</td>
<td><strong>Phishing score</strong> A score between 1-8. Anything 3 or under is good. [1]</td>
</tr>
<tr>
<td>X-Microsoft-Antispam: BCL:</td>
<td><strong>Bulk sending score</strong> A score between 0-9. Anything 3 or under is good. [2]</td>
</tr>
<tr>
<td>X-MS-Exchange-Organization-SCL:</td>
<td><strong>Spam confidence level</strong> A score between 0-9. Anything under 5 is good. [3]</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Email services use a number of rules and tools to determine the SPAM Confidence Level. This based upon the language and email style.</p><p><strong>References</strong><br>[1] <a href="https://learn.microsoft.com/en-us/exchange/antispam-and-antimalware/antispam-protection/antispam-stamps?view=exchserver-2019#the-phishing-confidence-level-stamp">https://learn.microsoft.com/en-us/exchange/antispam-and-antimalware/antispam-protection/antispam-stamps?view=exchserver-2019#the-phishing-confidence-level-stamp</a><br>[2] <a href="https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/anti-spam-bulk-complaint-level-bcl-about?view=o365-worldwide">https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/anti-spam-bulk-complaint-level-bcl-about?view=o365-worldwide</a><br>[3] <a href="https://learn.microsoft.com/en-us/exchange/antispam-and-antimalware/antispam-protection/antispam-stamps?view=exchserver-2019#the-spam-confidence-level-stamp">https://learn.microsoft.com/en-us/exchange/antispam-and-antimalware/antispam-protection/antispam-stamps?view=exchserver-2019#the-spam-confidence-level-stamp</a></p>]]></content:encoded></item><item><title><![CDATA[SignBSL Year in Review 2022]]></title><description><![CDATA[<p>Quick recap of this year&apos;s search data for SignBSL <strong>23,595,029</strong> searches were done. This is a tiny increase of <strong>+0.6%</strong> from last year. So almost unchanged the amount of searches. Below I have included the <strong>top 50 most searched words</strong>.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Search Query</th>
<th>No. Searches</th>
<th>% Change</th></tr></thead></table>]]></description><link>https://www.daniel-mitchell.com/blog/signbsl-year-in-review-2022/</link><guid isPermaLink="false">63b59518679c4b63757944a1</guid><category><![CDATA[Sign Language]]></category><category><![CDATA[Year in Review]]></category><category><![CDATA[SignBSL]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Tue, 10 Jan 2023 20:58:53 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2023/01/Adobe_Express_20230110_2056480_1-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2023/01/Adobe_Express_20230110_2056480_1-1.png" alt="SignBSL Year in Review 2022"><p>Quick recap of this year&apos;s search data for SignBSL <strong>23,595,029</strong> searches were done. This is a tiny increase of <strong>+0.6%</strong> from last year. So almost unchanged the amount of searches. Below I have included the <strong>top 50 most searched words</strong>.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Search Query</th>
<th>No. Searches</th>
<th>% Change from last year</th>
</tr>
</thead>
<tbody>
<tr>
<td>how are you</td>
<td>45,911</td>
<td>-16%</td>
</tr>
<tr>
<td>i love you</td>
<td>42,692</td>
<td>26%</td>
</tr>
<tr>
<td>want</td>
<td>30,697</td>
<td>2%</td>
</tr>
<tr>
<td>how</td>
<td>27,340</td>
<td>-2%</td>
</tr>
<tr>
<td>good morning</td>
<td>26,995</td>
<td>13%</td>
</tr>
<tr>
<td>what</td>
<td>25,895</td>
<td>-15%</td>
</tr>
<tr>
<td>happy</td>
<td>24,989</td>
<td>-22%</td>
</tr>
<tr>
<td>my name is</td>
<td>24,245</td>
<td>-25%</td>
</tr>
<tr>
<td>with</td>
<td>24,173</td>
<td>20%</td>
</tr>
<tr>
<td>thank you</td>
<td>24,144</td>
<td>-10%</td>
</tr>
<tr>
<td>hello</td>
<td>23,747</td>
<td>-31%</td>
</tr>
<tr>
<td>when</td>
<td>23,348</td>
<td>9%</td>
</tr>
<tr>
<td>why</td>
<td>22,706</td>
<td>2%</td>
</tr>
<tr>
<td>more</td>
<td>22,277</td>
<td>7%</td>
</tr>
<tr>
<td>no</td>
<td>22,253</td>
<td>-10%</td>
</tr>
<tr>
<td>like</td>
<td>22,155</td>
<td>-11%</td>
</tr>
<tr>
<td>have</td>
<td>19,241</td>
<td>-13%</td>
</tr>
<tr>
<td>toilet</td>
<td>19,054</td>
<td>5%</td>
</tr>
<tr>
<td>tired</td>
<td>18,879</td>
<td>-33%</td>
</tr>
<tr>
<td>and</td>
<td>18,608</td>
<td>-36%</td>
</tr>
<tr>
<td>where</td>
<td>18,325</td>
<td>-1%</td>
</tr>
<tr>
<td>love</td>
<td>18,216</td>
<td>-18%</td>
</tr>
<tr>
<td>you&apos;re welcome</td>
<td>18,194</td>
<td>58%</td>
</tr>
<tr>
<td>do</td>
<td>17,753</td>
<td>-22%</td>
</tr>
<tr>
<td>today</td>
<td>17,332</td>
<td>5%</td>
</tr>
<tr>
<td>water</td>
<td>16,808</td>
<td>15%</td>
</tr>
<tr>
<td>go</td>
<td>16,400</td>
<td>-9%</td>
</tr>
<tr>
<td>school</td>
<td>16,277</td>
<td>0%</td>
</tr>
<tr>
<td>beautiful</td>
<td>16,048</td>
<td>-10%</td>
</tr>
<tr>
<td>holiday</td>
<td>16,029</td>
<td>33%</td>
</tr>
<tr>
<td>please</td>
<td>15,862</td>
<td>-13%</td>
</tr>
<tr>
<td>sorry</td>
<td>15,723</td>
<td>-14%</td>
</tr>
<tr>
<td>who</td>
<td>15,664</td>
<td>-6%</td>
</tr>
<tr>
<td>dictionary</td>
<td>15,462</td>
<td>300%</td>
</tr>
<tr>
<td>yes</td>
<td>15,383</td>
<td>-14%</td>
</tr>
<tr>
<td>dog</td>
<td>15,347</td>
<td>-12%</td>
</tr>
<tr>
<td>can</td>
<td>15,227</td>
<td>-23%</td>
</tr>
<tr>
<td>help</td>
<td>15,179</td>
<td>-14%</td>
</tr>
<tr>
<td>good</td>
<td>14,772</td>
<td>-21%</td>
</tr>
<tr>
<td>need</td>
<td>14,752</td>
<td>-9%</td>
</tr>
<tr>
<td>friend</td>
<td>14,678</td>
<td>-13%</td>
</tr>
<tr>
<td>i</td>
<td>14,606</td>
<td>-45%</td>
</tr>
<tr>
<td>you</td>
<td>14,456</td>
<td>-37%</td>
</tr>
<tr>
<td>tomorrow</td>
<td>14,209</td>
<td>8%</td>
</tr>
<tr>
<td>play</td>
<td>13,761</td>
<td>-6%</td>
</tr>
<tr>
<td>work</td>
<td>13,526</td>
<td>7%</td>
</tr>
<tr>
<td>green</td>
<td>13,425</td>
<td>-2%</td>
</tr>
<tr>
<td>word</td>
<td>13,405</td>
<td>-19%</td>
</tr>
<tr>
<td>favourite</td>
<td>13,382</td>
<td>2%</td>
</tr>
<tr>
<td>know</td>
<td>13,380</td>
<td>-10%</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[SignASL Year in Review 2022]]></title><description><![CDATA[<p>Quick recap of this year&apos;s search data for SignASL <strong>26,274,632</strong> searches were done. This is a small increase of <strong>+5.6%</strong> from last year. Below I have included the <strong>top 50 most searched words</strong>.</p><p>The top 5 words are offensive words. In fact there are 7</p>]]></description><link>https://www.daniel-mitchell.com/blog/signasl-year-in-review-2022/</link><guid isPermaLink="false">63b597b7679c4b63757944d7</guid><category><![CDATA[SignASL]]></category><category><![CDATA[Sign Language]]></category><category><![CDATA[Year in Review]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Tue, 10 Jan 2023 20:58:18 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2023/01/Adobe_Express_20230110_2056480_1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2023/01/Adobe_Express_20230110_2056480_1.png" alt="SignASL Year in Review 2022"><p>Quick recap of this year&apos;s search data for SignASL <strong>26,274,632</strong> searches were done. This is a small increase of <strong>+5.6%</strong> from last year. Below I have included the <strong>top 50 most searched words</strong>.</p><p>The top 5 words are offensive words. In fact there are 7 offensive words in the top 50, unlike users searching for BSL where none of the top 50 include such words. Of note from 2022 is the word &apos;<strong>Ukraine</strong>&apos; enters into the <strong>top 50</strong> with a <strong>688%</strong> increase from last year. The word &apos;<strong>God</strong>&apos; dropped from position <strong>2</strong> to position <strong>42</strong>.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Search Query</th>
<th>No. Searches</th>
<th>% Change</th>
</tr>
</thead>
<tbody>
<tr>
<td>****</td>
<td>31,884</td>
<td>227%</td>
</tr>
<tr>
<td>****</td>
<td>28,194</td>
<td>43%</td>
</tr>
<tr>
<td>****</td>
<td>21,706</td>
<td>711%</td>
</tr>
<tr>
<td>****</td>
<td>17,849</td>
<td>30%</td>
</tr>
<tr>
<td>****</td>
<td>17,038</td>
<td>95%</td>
</tr>
<tr>
<td>good</td>
<td>14,660</td>
<td>17%</td>
</tr>
<tr>
<td>have</td>
<td>14,586</td>
<td>16%</td>
</tr>
<tr>
<td>what</td>
<td>14,275</td>
<td>13%</td>
</tr>
<tr>
<td>like</td>
<td>14,182</td>
<td>28%</td>
</tr>
<tr>
<td>how</td>
<td>14,082</td>
<td>20%</td>
</tr>
<tr>
<td>ukraine</td>
<td>14,059</td>
<td>688%</td>
</tr>
<tr>
<td>****</td>
<td>13,990</td>
<td>263%</td>
</tr>
<tr>
<td>when</td>
<td>13,585</td>
<td>22%</td>
</tr>
<tr>
<td>****</td>
<td>12,645</td>
<td>86%</td>
</tr>
<tr>
<td>want</td>
<td>12,643</td>
<td>10%</td>
</tr>
<tr>
<td>love</td>
<td>12,490</td>
<td>12%</td>
</tr>
<tr>
<td>peace</td>
<td>12,421</td>
<td>62%</td>
</tr>
<tr>
<td>thank you</td>
<td>12,204</td>
<td>21%</td>
</tr>
<tr>
<td>is</td>
<td>12,047</td>
<td>7%</td>
</tr>
<tr>
<td>and</td>
<td>11,857</td>
<td>9%</td>
</tr>
<tr>
<td>do</td>
<td>11,786</td>
<td>21%</td>
</tr>
<tr>
<td>favorite</td>
<td>11,679</td>
<td>15%</td>
</tr>
<tr>
<td>with</td>
<td>11,672</td>
<td>24%</td>
</tr>
<tr>
<td>where</td>
<td>11,609</td>
<td>27%</td>
</tr>
<tr>
<td>hello</td>
<td>11,567</td>
<td>16%</td>
</tr>
<tr>
<td>happy</td>
<td>11,428</td>
<td>13%</td>
</tr>
<tr>
<td>how are you</td>
<td>11,187</td>
<td>35%</td>
</tr>
<tr>
<td>school</td>
<td>11,127</td>
<td>15%</td>
</tr>
<tr>
<td>you&apos;re welcome</td>
<td>11,049</td>
<td>-4%</td>
</tr>
<tr>
<td>to</td>
<td>11,038</td>
<td>15%</td>
</tr>
<tr>
<td>i</td>
<td>10,984</td>
<td>9%</td>
</tr>
<tr>
<td>go</td>
<td>10,836</td>
<td>14%</td>
</tr>
<tr>
<td>did</td>
<td>10,611</td>
<td>28%</td>
</tr>
<tr>
<td>no more</td>
<td>10,574</td>
<td>102%</td>
</tr>
<tr>
<td>ill be right back</td>
<td>10,413</td>
<td>-4%</td>
</tr>
<tr>
<td>went</td>
<td>10,348</td>
<td>-5%</td>
</tr>
<tr>
<td>can</td>
<td>10,342</td>
<td>28%</td>
</tr>
<tr>
<td>need</td>
<td>10,299</td>
<td>25%</td>
</tr>
<tr>
<td>why</td>
<td>10,247</td>
<td>12%</td>
</tr>
<tr>
<td>god</td>
<td>10,116</td>
<td>-30%</td>
</tr>
<tr>
<td>dog</td>
<td>9,807</td>
<td>8%</td>
</tr>
<tr>
<td>help</td>
<td>9,769</td>
<td>25%</td>
</tr>
<tr>
<td>glory</td>
<td>9,647</td>
<td>80%</td>
</tr>
<tr>
<td>grace</td>
<td>9,439</td>
<td>28%</td>
</tr>
<tr>
<td>please</td>
<td>9,395</td>
<td>19%</td>
</tr>
<tr>
<td>we</td>
<td>9,356</td>
<td>15%</td>
</tr>
<tr>
<td>in</td>
<td>9,355</td>
<td>19%</td>
</tr>
<tr>
<td>play</td>
<td>9,324</td>
<td>19%</td>
</tr>
<tr>
<td>no</td>
<td>9,320</td>
<td>27%</td>
</tr>
<tr>
<td>glitter</td>
<td>9,235</td>
<td>1291%</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Inbox Zero in Outlook without deleting an email]]></title><description><![CDATA[<p>Many email organisers recommend a ruthless approach to email management. However, for me, email is an important record of all conversations and a record of what happened, it forms a journal of important details, which I rely upon when needed. Therefore deleting email is not an option. Yet, still finding</p>]]></description><link>https://www.daniel-mitchell.com/blog/inbox-zero-in-outlook-without-deleting-an-email/</link><guid isPermaLink="false">62e7aa2fa8064c501e7a4c1d</guid><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Tue, 02 Aug 2022 10:45:00 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2022/08/Adobe_Express_20220803_2309540_1.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2022/08/Adobe_Express_20220803_2309540_1.png" alt="Inbox Zero in Outlook without deleting an email"><p>Many email organisers recommend a ruthless approach to email management. However, for me, email is an important record of all conversations and a record of what happened, it forms a journal of important details, which I rely upon when needed. Therefore deleting email is not an option. Yet, still finding emails that need to be answered or emails that represents a task I need to complete is important. So, being faced with a massive list that requires lots of scrolling is not optimal either.</p><p>The solution, is to create a customised view in Outlook. The only emails I want to see most of the time our emails that have not yet been read, or emails I have flagged because they represent some kind of task or action I need to take.</p><p>To do this take advantage of the <code>Change View</code> feature in Outlook. Click the little arrow three buttons in from the top left. And then choose <code>Manage Views...</code></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.daniel-mitchell.com/content/images/2022/08/image.png" class="kg-image" alt="Inbox Zero in Outlook without deleting an email" loading="lazy" width="384" height="191"><figcaption>Outlook - Change View | Manage Views</figcaption></figure><p>This brings up a new window which allows you to Manage Views.</p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/08/image-2.png" class="kg-image" alt="Inbox Zero in Outlook without deleting an email" loading="lazy" width="478" height="431"></figure><p>We can then choose <code>New</code>. I give it a title of <code>90 days Unread or Flagged</code></p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/08/image-4.png" class="kg-image" alt="Inbox Zero in Outlook without deleting an email" loading="lazy" width="260" height="332"></figure><p>Choose <code>Filter</code></p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/08/image-5.png" class="kg-image" alt="Inbox Zero in Outlook without deleting an email" loading="lazy" width="489" height="334"></figure><p>Select the tab <code>SQL</code> and then <code>Edit these criteria directly</code> and paste in the following statement.</p><pre><code>((&quot;urn:schemas:httpmail:read&quot; = 0) OR (&quot;http://schemas.microsoft.com/mapi/proptag/0x10900003&quot; &gt; 1)) AND (&quot;urn:schemas:httpmail:datereceived&quot; &gt; today(-7776000))</code></pre><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/08/image-6.png" class="kg-image" alt="Inbox Zero in Outlook without deleting an email" loading="lazy" width="415" height="320"></figure><p>This will then filter emails that are unread or have been flagged. And only if the emails are less than 90 days. (After all if you have not responded to them in 90 days they are no longer so important!)</p><p>Then choose this new view from the <code>Change View</code> icon.</p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/08/image-8.png" class="kg-image" alt="Inbox Zero in Outlook without deleting an email" loading="lazy" width="377" height="242"></figure><p>Now you can enjoy the advantages of Inbox Zero of a small mailbox with only the most important messages displayed. Yet all those important emails that are a record of your life still intact. Enjoy!</p>]]></content:encoded></item><item><title><![CDATA[Low Latency Serverless Typeahead using CloudFlare Workers]]></title><description><![CDATA[<p>Helping users find what they want fast is essential for a good user experience. Using a typeahead input box allows this. But to be effective it needs to be fast.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.daniel-mitchell.com/content/images/2022/03/chrome_RLhXav3zwo.png" class="kg-image" alt loading="lazy" width="500" height="318"><figcaption>Typeahead search at www.signasl.org</figcaption></figure><p>The fastest solution would be to have all the search entries available locally on</p>]]></description><link>https://www.daniel-mitchell.com/blog/low-latency-serverless-typeahead-using-cloudflare-workers/</link><guid isPermaLink="false">623082f3f5182902cf04a8a3</guid><category><![CDATA[CloudFlare]]></category><dc:creator><![CDATA[Daniel Mitchell]]></dc:creator><pubDate>Mon, 28 Mar 2022 14:50:53 GMT</pubDate><media:content url="https://www.daniel-mitchell.com/content/images/2022/03/CC_Express_20220323_2219550.00875124408366057.png" medium="image"/><content:encoded><![CDATA[<img src="https://www.daniel-mitchell.com/content/images/2022/03/CC_Express_20220323_2219550.00875124408366057.png" alt="Low Latency Serverless Typeahead using CloudFlare Workers"><p>Helping users find what they want fast is essential for a good user experience. Using a typeahead input box allows this. But to be effective it needs to be fast.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.daniel-mitchell.com/content/images/2022/03/chrome_RLhXav3zwo.png" class="kg-image" alt="Low Latency Serverless Typeahead using CloudFlare Workers" loading="lazy" width="500" height="318"><figcaption>Typeahead search at www.signasl.org</figcaption></figure><p>The fastest solution would be to have all the search entries available locally on the browser. But for this website there is currently 41,046 entries, taking 508kb of data. (gzip compression helps, but would still require 167kb of data to be sent over the wire). Sending this amount of data is not only slow, but also costly. With over 200,000 monthly users that would result in nearly 100GB of egress charges (33GB if compressed). Unlike website images this data can not be aggressively cached. For the typeahead search to be most useful this list needs to be regularly updated, not only for the latest search terms but also its order. Commonly searched or trending words need to be given priority in the list over less frequently searched words. To do this I update the search terms JSON file every 20 minutes.</p><p>So how can we make the typeahead fast but not burden the end user with a large JSON file? The trick is to bring that JSON file as close to the end users and then only transmit the entries they need to see as and when they request it. To do this I will use CloudFlare Workers, allowing me to leverage CloudFlare&apos;s global network of data centres. A Worker allows for a script size up to 1MB. This allows the whole dataset of all search terms to be stored. This script is then deployed to their edge locations around the world. The Worker can then take the search query requests and then filter the data, returning just a few rows to be displayed. CloudFlare provides up to 100,000 Worker requests per day, meaning that this performant, low latency typeahead can be deployed for free.</p><p><strong>Setup</strong></p><p>Select <code>Workers</code> from the CloudFlare menu on the left. Then choose <code>Create a Service</code></p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/03/suGWBXNx7B.png" class="kg-image" alt="Low Latency Serverless Typeahead using CloudFlare Workers" loading="lazy" width="1321" height="640" srcset="https://www.daniel-mitchell.com/content/images/size/w600/2022/03/suGWBXNx7B.png 600w, https://www.daniel-mitchell.com/content/images/size/w1000/2022/03/suGWBXNx7B.png 1000w, https://www.daniel-mitchell.com/content/images/2022/03/suGWBXNx7B.png 1321w" sizes="(min-width: 720px) 720px"></figure><p>Enter a name and choose <code>HTTP Handler</code></p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/03/chrome_YtHz9ELDM6.png" class="kg-image" alt="Low Latency Serverless Typeahead using CloudFlare Workers" loading="lazy" width="1330" height="882" srcset="https://www.daniel-mitchell.com/content/images/size/w600/2022/03/chrome_YtHz9ELDM6.png 600w, https://www.daniel-mitchell.com/content/images/size/w1000/2022/03/chrome_YtHz9ELDM6.png 1000w, https://www.daniel-mitchell.com/content/images/2022/03/chrome_YtHz9ELDM6.png 1330w" sizes="(min-width: 720px) 720px"></figure><p>Next under <code>Triggers</code> setup the path that this worker should respond on. In my case this was <code>www.signasl.org/wordsearch.php*</code> so that it could replace the existing server side method. This will mean a CloudFlare Worker nearest to the user will respond to the request rather than it having to travel to the single server in <code>eu-west-1 </code>region. I also set the <code>Request limit failure mode</code> to <code>Fail open (proceed)</code> this way if I exceed the free tier allowance then the typeahead will continue to work by falling back to its original (albeit slower) functionality.</p><figure class="kg-card kg-image-card"><img src="https://www.daniel-mitchell.com/content/images/2022/03/chrome_AdLC0q9TQ8.png" class="kg-image" alt="Low Latency Serverless Typeahead using CloudFlare Workers" loading="lazy" width="970" height="746" srcset="https://www.daniel-mitchell.com/content/images/size/w600/2022/03/chrome_AdLC0q9TQ8.png 600w, https://www.daniel-mitchell.com/content/images/2022/03/chrome_AdLC0q9TQ8.png 970w" sizes="(min-width: 720px) 720px"></figure><p>Next step is to automate the updating of the Worker script including the large JSON array of search data. To do this you need to make a note of your CloudFlare AccountId, the name of the Worker Script and create credentials <a href="https://dash.cloudflare.com/profile/api-tokens">here</a> that have permission to update this Worker script.</p><p>For me, I already have an existing C# AWS Lambda Function that I use to calculate recently searched data to make the typeahead ordering more helpful. This function already outputs the search options as a JSON file to S3. So I will add in an API call to this existing function to make an update to the Worker script.</p><p>The basic CURL command is:</p><pre><code class="language-CURL">curl -X PUT &quot;https://api.cloudflare.com/client/v4/accounts/YOUR-ACCOUNT-ID/workers/scripts/typeahead-asl&quot; \
     -H &quot;Authorization: Bearer YOUR-TOKEN-HERE&quot; \
     -H &quot;Content-Type: application/javascript&quot; \
     --data &quot;SCRIPT DATA HERE&quot;</code></pre><p>My C# code in part looks like:</p><pre><code class="language-c#">var requestContent = new StringContent(GetWorkerScript(jsonString), Encoding.UTF8, &quot;application/javascript&quot;);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(&quot;Bearer&quot;, CloudFlareWorkerBearerToken);
client.PutAsync($&quot;https://api.cloudflare.com/client/v4/accounts/{CloudFlareAccountId}/workers/scripts/{scriptName}&quot;, requestContent).Result;</code></pre><p>The <code>GetWorkerScript</code> function produces the JavaScript output:</p><pre><code class="language-JavaScript">var globalData = [&quot;WORD&quot;,&quot;LIST&quot;,&quot;ARRAY&quot;];

addEventListener(&quot;fetch&quot;, event =&gt; {
    event.respondWith(handleRequest(event.request))
})

async function handleRequest(request)
{
    const url = new URL(request.url);
    if (!url.pathname.startsWith(&apos;/wordsearch.php&apos;)) return fetch(request);

    const { pathname, searchParams} = new URL(request.url)
    const query = (searchParams.get(&apos;query&apos;) || &apos;&apos;).toLowerCase();
    
    var data = globalData;
    if (query != &apos;&apos;)
    {
        data = data.filter(word =&gt; word.toLowerCase().includes(query));

        data = data.sort((a, b) =&gt; {
            // Give priority to exact matches
            if (a.toLowerCase() == query)
            {
                return -1;
            }
            if (b.toLowerCase() == query)
            {
                return 1;
            }

            const aPos = a.toLowerCase().indexOf(query);
            const bPos = b.toLowerCase().indexOf(query);

            if (aPos &lt; 0)
            {
                if (bPos &lt; 0)
                {
                    return 0;
                }

                return 1;
            }

            if (aPos &lt; bPos)
            {
                return -1;
            }
            else if (aPos &gt; bPos)
            {
                return 1;
            }
            else
            {
                return a - b;
                return 0; // neutral.
            }

            return 0;
        });

        if (data.length &gt; 30)
        {
            data.length = 30; // Return just a small number of results for this specific search.
        }
    }
    else
    {
        // If no search result then return a large number of results to initially populate the typeahead search.
        data = data.slice(0, 4000);
    }

    response = new Response(JSON.stringify(data));
    response.headers.set(&apos;content-type&apos;, &apos;application/json;charset=UTF-8&apos;);
    return response;
}</code></pre><p>The first line contains a Global Variable that lists all the search words ordered by how commonly searched for the word is. This Global Variable persists between executions giving a super fast in memory cache. Making subsequent requests lightning fast.</p><blockquote>Only one Workers instance runs on each of the many global Cloudflare edge servers. Each Workers instance can consume up to 128MB of memory. Use global variables to persist data between requests on individual nodes as a super fast cache. Note: As the global variable is shared across requests, you must make sure you do not edit its content as that would then affect subsequent requests.</blockquote><p>A basic filter at the beginning only respond to the expected requests. Although it should never respond to other requests as I have specified a specific request in the route setup.</p><p>Then it uses the array <code>filter</code> function followed by a custom <code>sort</code> which allows me to prioritise searches where matches appear nearer the beginning of the word. If someone searches for <em>ma</em> they are much more likely to be looking for <em><u>ma</u>n</em> or <em><u>ma</u>nkind</em> rather than looking for <em>ani<u>ma</u>l</em>. If the position of the search term in the word is the same, then do not change the ordering, which will mean the pre-ordered list of words will return the most commonly searched for words.</p><p>This sorted list is then <code>JSON.stringify</code> and returned as JSON. Giving the following results when the user has entered <em>ma</em>:</p><pre><code class="language-json">[&quot;ma&quot;, &quot;make&quot;, &quot;made&quot;, &quot;magic&quot;, &quot;man&quot;, &quot;management&quot;, &quot;Mac&quot;, &quot;Maker&quot;, &quot;maths&quot;, &quot;maybe&quot;, &quot;make up&quot;, &quot;March&quot;, &quot;market&quot;, &quot;Macintosh&quot;, &quot;mainstream&quot;, &quot;Makaton&quot;, &quot;Malaysia&quot;, &quot;manager&quot;, &quot;math&quot;, &quot;magnet&quot;, &quot;magnetic flux&quot;, &quot;main&quot;, &quot;mango&quot;, &quot;many&quot;, &quot;masking&quot;, &quot;May&quot;, &quot;magazine&quot;, &quot;mammal&quot;, &quot;managing director&quot;, &quot;map&quot;]</code></pre><p>Giving me responses between 30-40ms. With none of these requests hitting the origin server. Globally performance will be limited not by how close they are to the origin server, but solely based upon how far they are from a CloudFlare edge server.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.daniel-mitchell.com/content/images/2022/03/image.png" class="kg-image" alt="Low Latency Serverless Typeahead using CloudFlare Workers" loading="lazy" width="1329" height="952" srcset="https://www.daniel-mitchell.com/content/images/size/w600/2022/03/image.png 600w, https://www.daniel-mitchell.com/content/images/size/w1000/2022/03/image.png 1000w, https://www.daniel-mitchell.com/content/images/2022/03/image.png 1329w" sizes="(min-width: 720px) 720px"><figcaption>Summary of the Worker Requests</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.daniel-mitchell.com/content/images/2022/03/image-1.png" class="kg-image" alt="Low Latency Serverless Typeahead using CloudFlare Workers" loading="lazy" width="1064" height="818" srcset="https://www.daniel-mitchell.com/content/images/size/w600/2022/03/image-1.png 600w, https://www.daniel-mitchell.com/content/images/size/w1000/2022/03/image-1.png 1000w, https://www.daniel-mitchell.com/content/images/2022/03/image-1.png 1064w" sizes="(min-width: 720px) 720px"><figcaption>CPU Time per execution.</figcaption></figure>]]></content:encoded></item></channel></rss>