<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>hi, it&#39;s mike</title>
    <link>https://mike.puddingtime.org/tags/plaintextcrm/</link>
    <description>Recent content on hi, it&#39;s mike</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>mike@puddingtime.org (mike)</managingEditor>
    <webMaster>mike@puddingtime.org (mike)</webMaster>
    <copyright>© 2026, mike</copyright>
    <lastBuildDate>Tue, 18 Apr 2023 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://mike.puddingtime.org/tags/plaintextcrm/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Extending the plaintext CRM to mail contacts</title>
      <link>https://mike.puddingtime.org/posts/2023-04-18-extending-the-plaintext-crm-to-mail-contacts/</link>
      <pubDate>Tue, 18 Apr 2023 00:00:00 +0000</pubDate><author>mike@puddingtime.org (mike)</author>
      <guid>https://mike.puddingtime.org/posts/2023-04-18-extending-the-plaintext-crm-to-mail-contacts/</guid>
      <description>Added a little automation to contacts.org with a function that auto-populates a message buffer in mu4e.</description>
      <content:encoded><![CDATA[<p>I did some menu cleanup and refactor today to get my plaintext CRM into a slightly more mnemonic state. Here are the mappings, which are readable enough:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nv">map!</span> <span class="nb">:mode</span> <span class="nv">org</span>
</span></span><span class="line"><span class="cl">      <span class="nb">:leader</span>
</span></span><span class="line"><span class="cl">     <span class="p">(</span><span class="nb">:prefix-map</span> <span class="p">(</span><span class="s">&#34;C&#34;</span> <span class="o">.</span> <span class="s">&#34;CRM&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">:desc</span> <span class="s">&#34;Schedule Contact&#34;</span> <span class="s">&#34;s&#34;</span> <span class="nf">#&#39;</span><span class="nv">org-schedule-heading</span>
</span></span><span class="line"><span class="cl">        <span class="nb">:desc</span> <span class="s">&#34;Clear TODO states&#34;</span> <span class="s">&#34;z&#34;</span> <span class="nf">#&#39;</span><span class="nv">my/org-remove-todo</span>
</span></span><span class="line"><span class="cl">        <span class="nb">:desc</span> <span class="s">&#34;Update CONTACTED to today&#34;</span> <span class="s">&#34;t&#34;</span> <span class="nf">#&#39;</span><span class="nv">org-set-contacted-today</span>
</span></span><span class="line"><span class="cl">        <span class="nb">:desc</span> <span class="s">&#34;Update CONTACTED to ...&#34;</span> <span class="s">&#34;d&#34;</span> <span class="nf">#&#39;</span><span class="nv">org-set-contacted-date</span>
</span></span><span class="line"><span class="cl">        <span class="nb">:desc</span> <span class="s">&#34;SCHEDULE a date&#34;</span> <span class="s">&#34;S&#34;</span> <span class="nf">#&#39;</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span> <span class="p">(</span><span class="nv">my/org-set-heading-state-and-time</span> <span class="s">&#34;&#34;</span> <span class="mi">30</span> <span class="ss">&#39;s</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="nb">:desc</span> <span class="s">&#34;Mail this contact&#34;</span> <span class="s">&#34;m&#34;</span> <span class="nf">#&#39;</span><span class="nv">my-org-contacts-email</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">     <span class="p">(</span><span class="nb">:prefix-map</span> <span class="p">(</span><span class="s">&#34;C r&#34;</span><span class="o">.</span> <span class="s">&#34;Remember to ...&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">       <span class="nb">:desc</span> <span class="s">&#34;... write within 7 days&#34;</span> <span class="s">&#34;w&#34;</span> <span class="nf">#&#39;</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span> <span class="p">(</span><span class="nv">my/org-set-heading-state-and-time</span> <span class="s">&#34;WRITE&#34;</span> <span class="mi">7</span> <span class="ss">&#39;d</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">       <span class="nb">:desc</span> <span class="s">&#34;... followup in 3 days&#34;</span> <span class="s">&#34;f&#34;</span> <span class="nf">#&#39;</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span> <span class="p">(</span><span class="nv">my/org-set-heading-state-and-time</span> <span class="s">&#34;FOLLOWUP&#34;</span> <span class="mi">3</span> <span class="ss">&#39;s</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">       <span class="nb">:desc</span> <span class="s">&#34;... ping within 7 days&#34;</span> <span class="s">&#34;p&#34;</span> <span class="nf">#&#39;</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span> <span class="p">(</span><span class="nv">my/org-set-heading-state-and-time</span> <span class="s">&#34;PING&#34;</span> <span class="mi">3</span> <span class="ss">&#39;d</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">       <span class="nb">:desc</span> <span class="s">&#34;... invite within 3 days&#34;</span> <span class="s">&#34;i&#34;</span> <span class="nf">#&#39;</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span> <span class="p">(</span><span class="nv">my/org-set-heading-state-and-time</span> <span class="s">&#34;INVITE&#34;</span> <span class="mi">3</span> <span class="ss">&#39;d</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div>
<p>It&rsquo;s a bunch of &ldquo;tap the leader key, tap &ldquo;<code>C</code>&rdquo; for &ldquo;CRM,&rdquo; then do some common stuff,&rdquo; like setting deadlines to write someone, or update the <code>:CONTACTED:</code> property, or just set the <code>SCHEDULED:</code> date on a record. This is the <code>my/org-set-heading-state-and-time</code> function:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">my/org-set-heading-state-and-time</span> <span class="p">(</span><span class="nv">state</span> <span class="nv">days</span> <span class="kp">&amp;optional</span> <span class="nv">time-type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Sets the TODO state and deadline or scheduled date of the current heading.
</span></span></span><span class="line"><span class="cl"><span class="s">   STATE is the new TODO state to set, and DAYS is the number
</span></span></span><span class="line"><span class="cl"><span class="s">   of days from the current date to set the new time. If TIME-TYPE
</span></span></span><span class="line"><span class="cl"><span class="s">   is &#39;d&#39;, sets a deadline; if &#39;s&#39;, sets a scheduled date; otherwise,
</span></span></span><span class="line"><span class="cl"><span class="s">   prompts the user for the time type. Removes any existing schedules
</span></span></span><span class="line"><span class="cl"><span class="s">   or deadlines before setting the new time.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span> <span class="p">(</span><span class="nf">list</span> <span class="s">&#34;WRITE&#34;</span> <span class="mi">7</span> <span class="no">nil</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">org-entry-put</span> <span class="no">nil</span> <span class="s">&#34;TODO&#34;</span> <span class="nv">state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nv">org-entry-get</span> <span class="no">nil</span> <span class="s">&#34;DEADLINE&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">org-entry-delete</span> <span class="no">nil</span> <span class="s">&#34;DEADLINE&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nv">org-entry-get</span> <span class="no">nil</span> <span class="s">&#34;SCHEDULED&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">org-entry-delete</span> <span class="no">nil</span> <span class="s">&#34;SCHEDULED&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">new-time</span> <span class="p">(</span><span class="nf">format-time-string</span> <span class="s">&#34;&lt;%Y-%m-%d %a&gt;&#34;</span>
</span></span><span class="line"><span class="cl">                                      <span class="p">(</span><span class="nf">time-add</span> <span class="p">(</span><span class="nf">current-time</span><span class="p">)</span> <span class="p">(</span><span class="nv">days-to-time</span> <span class="nv">days</span><span class="p">)))))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">cond</span> <span class="p">((</span><span class="nf">equal</span> <span class="nv">time-type</span> <span class="ss">&#39;d</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="p">(</span><span class="nv">org-deadline</span> <span class="no">nil</span> <span class="nv">new-time</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">          <span class="p">((</span><span class="nf">equal</span> <span class="nv">time-type</span> <span class="ss">&#39;s</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="p">(</span><span class="nv">org-schedule</span> <span class="no">nil</span> <span class="nv">new-time</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="no">t</span>
</span></span><span class="line"><span class="cl">           <span class="p">(</span><span class="nb">setq</span> <span class="nv">time-type</span> <span class="p">(</span><span class="nf">completing-read</span> <span class="s">&#34;Set time type (d/s): &#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">           <span class="p">(</span><span class="nv">my/org-set-heading-state-and-time</span> <span class="nv">state</span> <span class="nv">days</span> <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nv">string=</span> <span class="nv">time-type</span> <span class="s">&#34;d&#34;</span><span class="p">)</span> <span class="ss">&#39;d</span> <span class="ss">&#39;s</span><span class="p">))))))</span></span></span></code></pre></div>
<p>It&rsquo;s written with the menu system in mind. It&rsquo;d be too clunky to use interactively &ndash; too many possible states to remember, etc. but as part of a bunch of canned menu options you can get to with one or two taps it saves a bunch of typing and cursor motion for common operations.</p>
<p>Then I thought, &ldquo;it&rsquo;d be handy to just visit a record and have an option to compose a mail,&rdquo; so <code>my-org-contacts-email</code> was born:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">my-org-contacts-email</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Open am email message to the email address in the EMAIL property of the current org-contacts heading.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nf">eq</span> <span class="nv">major-mode</span> <span class="ss">&#39;org-mode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">email</span> <span class="p">(</span><span class="nv">org-entry-get</span> <span class="p">(</span><span class="nf">point</span><span class="p">)</span> <span class="s">&#34;EMAIL&#34;</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nb">if</span> <span class="nv">email</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nb">progn</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nb">unless</span> <span class="p">(</span><span class="nb">featurep</span> <span class="ss">&#39;mu4e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">              <span class="p">(</span><span class="nv">mu4e</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nv">mu4e-compose-new</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nv">message-goto-to</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nf">insert</span> <span class="nv">email</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nv">message-goto-body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nf">insert</span> <span class="s">&#34;\n\n&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">message</span> <span class="s">&#34;No email address found.&#34;</span><span class="p">)))))</span></span></span></code></pre></div>
<p>It has some behavioral issues I need to straighten out, but if mu4e is running and I tap <code>SPC C m</code> while positioned over a contact, it opens and pre-addresses a new message in mu4e.</p>
<p>I think it&rsquo;s beyond the ken of <code>org-caldav</code>, but I suppose a call out to AppleScript could create similar functionality for scheduling things with a contact.</p>
<p>I really like the Doom menu system (and I suppose I&rsquo;d like Spacemacs&rsquo; as well). The last time I was all-in on org mode I had so much trouble with all the Emacs chords that I ended up setting up <a href="https://gitlab.com/phillord/org-drill/">org-drill</a> to periodically train. With Doom&rsquo;s menus, there are decent mnemonics up front, then visual reminders along the way. It still takes time to learn everything, but you get reminders and you can stop to study the menu if you forget. I don&rsquo;t know how many times I have mashed <code>CTRL g</code> when I lost track of my fingers during a complex vanilla Emacs sequence.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
