Enviar e-mail escrito em markdown usando mutt

21

Às vezes, preciso enviar um fragmento de código no google-group inline. O texto não ajuda aqui; Eu posso digitar no markdown, convertê-lo em html (usando pandoc etc.), anexar ao mutt as text/htmle enviá-lo.

Há uma boa solução disponível aqui, mas ela usa sendmailprograma externo para enviar email. Estou usando o mutt, que possui recursos para enviar e - mails por IMAP por si só.

Dilawar
fonte
11
Por que não apenas canalizar a saída de um formatador de linha de comando para Markdown sendmail?
Naftuli Kay
Hmm .. computador compartilhado! Não deseja armazenar a senha do sendmail externo.
Dilawar
Existem exemplos de como são os resultados atuais nos grupos do Google?
slm
Você também deseja digitar as coisas na remarcação, mas processá-las antes de anexá-las aos seus e-mails, certo?
Slm
Parece o que você está pedindo, mas pode precisar ser modificado: dgl.cx/2009/03/html-mail-with-mutt-using-markdown . Também markdownmail.py parecia algo que você poderia usar.
Slm

Respostas:

28

Depois de escrever uma mensagem, mas antes de enviar, você tem muitas opções disponíveis. Pressione ?para vê-los.

Alguns que podem ajudar aqui:

  • F filtrar o anexo através de um processador externo
    • Use pandoc -s -f markdown -t htmlpara converter para HTML
  • ^T editar o tipo MIME do anexo
    • Mude de text/plainpara text/html.

Agora uma macro que fará tudo em uma única etapa. Adicione isso ao seu .muttrc:

macro compose \e5 "F pandoc -s -f markdown -t html \ny^T^Utext/html; charset=us-ascii\n"
set wait_key=no

Para usar essa macro, depois que você terminar de compor sua mensagem, mas antes de enviar, pressione Escem seguida, 5para converter sua mensagem de remarcação formatado em HTML.

Naturalmente, você pode personalizar essa macro como achar melhor. O Mutt já possui muitas combinações de teclas, portanto, independentemente da sequência de teclas que você escolher, certifique-se de que não substitua outra coisa (ou é algo que você pode viver sem).


A opção set wait_key=nosuprime o Press any key to continue...prompt do Mutt quando comandos externos são executados. Se wait_keyfor yes(que é o padrão), você precisará pressionar e Esc, em seguida 5, qualquer outra tecla para continuar.

bahamat
fonte
11
Esta é uma solução realmente elegante! +1
sinisterstuf
5
isso é legal, mas tem uma falha central. elimina a parte de texto sem formatação do e-mail, o que torna difícil ler em clientes como ... mutt;) Os e-mails em HTML devem ter um componente de texto sem formatação e html. a remarcação bruta deve ser o texto sem formatação, o convertido deve ser o HTML.
Masukomi
11
Concorde com o @masukomi, os clientes de e-mail em geral enviam as versões html e texto do e-mail. Seria bom ter uma macro que adicione a versão html e deixe o original como texto / sem formatação.
pepper_chico
2
No final, eu tenho construir a minha própria configuração para este nosubstance.me/post/mutt-secret-sauce
pepper_chico
1

O Sendmail geralmente não é flexível para enviar e-mails.

Eu uso o msmtp junto com o mutt em contas específicas para SMTP flexível.

Para usá-lo com mutt change:

# ~/.muttrc  
set sendmail="/usr/bin/msmtp -a default"   

e

# ~/.msmtprc  
defaults
tls off
logfile ~/.msmtp.log  
account default   
host your.smtp.host  
port 25  
from [email protected]  
auth off  
user username  
password password  

fonte
0

Eu fui capaz de fazer isso. Não estou totalmente feliz com minha solução, mas é decente o suficiente. Esperando que outra pessoa forneça uma solução melhor.

O processo está seguindo. Converta a marcação para html e anexe-a à mensagem. Transforme este anexo em inlineanexo. Mas agora eu tenho dois anexos, o primeiro é em remarcação e o segundo é em html. Substitua o conteúdo da remarcação por sequência vazia, para que apenas o html seja enviado.

Eu adicionei a seguinte linha ao ~/.muttrcarquivo.

macro compose B ":set editor=text2mime-markdown.py<enter>E:set editor=email-editor<enter>Da/tmp/html-markdown-alternative.html<enter>^Du"

Aqui está o email-editorque é emprestado do link postado em questão.

#!/bin/sh
if grep -q In-Reply-To $1; then
  # Jump to first line of message
  exec vim -c 'norm }j' $1
else
  # Enter insert mode on the To: line
  exec vim  $1
fi

E o principal arquivo python chamado é o seguinte. Isso é inspirado no script perl do link em questão.

#!/usr/bin/env python
import os
import sys
from formatter import *
version = "0.1"

file = sys.argv[1]
new_file = "/tmp/html-markdown-alternative.html"
with open(file, "r") as f:
    text = f.read()

lines = text.split('\n')
header = []
body = []
headerStart = True
for l in lines:
    if headerStart:
        m = re.search(r'^[\w\-]+\:', l)
        if m:
            header.append(l)
        else:
            headerStart = False
            body.append(l)
    else:
        body.append(l)

header = '\n'.join(header)
body = '\n'.join(body)

htmlBody = markdownToHtml(body);

html = []
html.append('<html>')
html.append('<head>')
html.append('<meta name=\"generator\" content=\"text2mime-markdown{}\">'.format(version))
html.append('<style>')
html.append("code { font-family: 'Andale Mono', 'Lucida Console', \
        'Bitstream Vera Sans Mono', 'Courier New', monospace; }")
html.append('pre { border-left: 20px solid #ddd; margin-left: 10px; \
        padding-left: 5px; }')
html.append('</style>')
html.append('</head>')
html.append('<body>')
html.append('{0}'.format(body))
html.append('</body>')
html.append('</html>')
html = '\n'.join(html)

with open(new_file, "w") as newF:
    newF.write(html)

with open(file, 'w') as f:
    f.write(header)

Isso depende de mais um arquivo python chamado formatter.pyque usa pandocpara formatar meu e-mail, mas se pandocnão estiver disponível, ele pode usar o python-markdown2pacote. Este script está seguindo.

import subprocess
import re
import os 
import sys
import html2text 
import collections

# check if pandoc exists
panDoc = True
try:
    subprocess.call(["pandoc", '--version']
            , stdout=subprocess.PIPE
            , stdin=subprocess.PIPE
            )
except OSError:
    panDoc = False

if not panDoc:
    import text.html2text as html2text
    import markdown 

def decodeText(text):
    return text.decode('utf-8')

def markdownToHtml(content, convertor='pandoc'):
    global panDoc
    if panDoc:
        cmd = ["pandoc", "-f", "markdown", "-t", "html"]
        p = subprocess.Popen(cmd
                , stdin = subprocess.PIPE
                , stdout = subprocess.PIPE
                )
        p.stdin.write(content)
        content = p.communicate()[0]
        return decodeText(content)
    else:
        return markdown.markdown(decodeText(content))


def htmlToMarkdown(content, convertor='pandoc'):
    global panDoc
    if panDoc and convertor == 'pandoc':
        cmd = ["pandoc", "-t", "markdown", "-f", "html"]
        p = subprocess.Popen(cmd
                , stdin = subprocess.PIPE
                , stdout = subprocess.PIPE
                )
        p.stdin.write(content)
        content = p.communicate()[0]
        return decodeText(content)
    # Use markdown package to convert markdown to html
    else:
        h = html2text.HTML2Text()
        content = h.handle(decodeText(content))
        return content

def titleToBlogDir(title):
    if title is None:
        return ''
    if len(title.strip()) == 0:
        return ''
    blogDir = title.replace(" ","_").replace(':', '-').replace('(', '')
    blogDir = blogDir.replace('/', '').replace('\\', '').replace('`', '')
    blogDir = blogDir.replace(')', '').replace("'", '').replace('"', '')
    return blogDir

def titleToFilePath(title, blogDir):
    if len(blogDir.strip()) == 0:
        return ''
    fileName = os.path.join(blogDir, titleToBlogDir(title))
    return fileName


def htmlToHtml(html):
    return decodeText(html)

def metadataDict(txt):
    mdict = collections.defaultdict(list)
    md = getMetadata(txt)
    for c in ["title", 'type', "layout", "status", "id", "published", "category", "tag"]:
        pat = re.compile(r'{0}\:\s*(?P<name>.+)'.format(c), re.IGNORECASE)
        m = pat.findall(txt)
        for i in m:
            mdict[c].append(i)
    return mdict

def getMetadata(txt):
   """
   Get metadata out of a txt
   """
   if not "---" in txt:
       print txt
       sys.exit(1)

   pat = re.compile(r'\-\-\-+(?P<metadata>.+?)\-\-\-+', re.DOTALL)
   m = pat.search(txt)
   if m:
       return m.group('metadata')
   else:
       sys.exit(0)

def getContent(txt):
    """ 
    Return only text of the post.
    """
    pat = re.compile(r'\-\-\-+(?P<metadata>.+?)\-\-\-+', re.DOTALL)
    return re.sub(pat, "", txt)

def readInputFile(fileName):
    """
    read file and return its format. html or markdown
    """
    assert fileName
    if not os.path.exists(fileName):
        raise IOError, "File %s does not exists" % fileName

    # Check the fmt of file.
    fmt = os.path.splitext(fileName)[1].lower()
    if fmt in ["htm", "html", "xhtml"]:
        fmt = "html"
    elif fmt in ["md", "markdown"]:
        fmt = "markdown"
    else:
        fmt = "markdown"
    txt = open(fileName, 'r').read()   
    return (fmt, txt)

def formatContent(txt, fmt):
    """
    Format the content as per fmt.
    """
    content = getContent(txt)
    if fmt == "html":
        content = htmlToHtml(content)
    elif fmt == "markdown":
        content = markdownToHtml(content)
    else:
        content = markdownToHtml(content)
    return content

Esses arquivos também estão disponíveis aqui https://github.com/dilawar/mutt

Dilawar
fonte
0

Posso enviar e-mail em qualquer formato usando neomutt. Eu apenas uso Emacs(modo org), em vez de vim. Embora eu também seja um vimusuário. Mas, eu uso principalmente Emacsno modo maligno.

No meu .muttrceu configurei o editor para ser em emacsvez de vim. Ao escrever um novo email, é neomuttacionado emacs. Então eu chamo "org-mode", escrevo a mensagem e exporto para o formato que desejar.

Eu posso exportar para o PDFformato. Em seguida, salve-o e anexe o PDFarquivo no meu /tmp. Depois disso, posso enviar para quem quiser.

Se eu quiser o htmlformato, exporto-o da mesma maneira e posso ver automaticamente a saída antes de enviar o email.

Além disso, existem muitos outros formatos de exportação no modo organizacional. Apenas escolha o que deseja. Para enviar código para outras pessoas, basta adicionar o código-fonte ao idioma desejado. Tudo é explicado no org-wiki .

Achylles
fonte
0

Você também pode enviar e-mails como multipart/alternativecontendo text/plaine text/html.

Requisitos: pandoc

Basicamente, ele cria a partir da mensagem de remarcação de texto sem formatação e html5. Cria anexos a partir dessas partes, marca-os como anexos embutidos, define o tipo correto de mímica e combina-os na mensagem mutlipart.

Quaisquer outros anexos devem ser adicionados após a execução dessa macro no menu de composição. Opcionalmente, a mensagem de assinatura / criptografia deve ser realizada como a etapa final

macro compose ,m \
"<enter-command>set pipe_decode<enter>\
<pipe-message>pandoc -f gfm -t plain -o /tmp/msg.txt<enter>\
<pipe-message>pandoc -s -f gfm -t html5 -o /tmp/msg.html<enter>\
<enter-command>unset pipe_decode<enter>a^U/tmp/msg.txt\n^Da^U/tmp/msg.html\n^D^T^Utext/html; charset=utf-8\n=DTT&d^U\n" \
"Convert markdown gfm to HTML and plain" 
Jakub Jindra
fonte