;; -*- lexical-binding: t; -*- ;;; main email system (require 'jao-afio) ;; (setq jao-afio-mail-function 'gnus) (setq jao-afio-mail-function 'notmuch) (defvar jao-notmuch-enabled (eq jao-afio-mail-function 'notmuch)) ;;; personal emails and others (defvar jao-mails) (defvar jao-extra-mails) (defvar jao-mails-regexp (regexp-opt jao-mails)) ;;; gnus (setq gnus-init-file "~/.emacs.d/gnus.el" gnus-home-directory "~/.emacs.d/gnus" gnus-directory gnus-home-directory gnus-cache-directory (expand-file-name "cache" gnus-home-directory) gnus-kill-files-directory (expand-file-name "News" gnus-home-directory) message-directory (expand-file-name "Mail" gnus-home-directory) mail-source-directory (expand-file-name "Mail" gnus-home-directory)) (let ((org-file (expand-file-name "gnus.org" jao-emacs-dir))) (when (file-newer-than-file-p org-file gnus-init-file) (org-babel-tangle-file org-file))) ;;; proton (use-package jao-proton-utils) ;;; message mode ;;;; customization (setq message-send-mail-function 'message-send-mail-with-sendmail message-sendmail-envelope-from 'header message-sendmail-f-is-evil nil) (setq imap-store-password t) (setq password-cache-expiry nil) (setq message-generate-headers-first t) (setq message-forward-before-signature nil) (setq message-alternative-emails (regexp-opt (append jao-mails jao-extra-mails))) (setq message-dont-reply-to-names (regexp-opt (append jao-mails '("noreply@" "@noreply" "no-reply@" "@no-reply" "notifications@github")))) (setq message-citation-line-format "On %a, %b %d %Y, %N wrote:\n") (setq message-citation-line-function 'message-insert-formatted-citation-line) (setq message-user-fqdn "mail.jao.io") (setq message-kill-buffer-on-exit t) (setq message-max-buffers 5) (setq message-insert-signature t) (setq message-from-style 'angles user-mail-address (car jao-mails) mail-host-address system-name message-syntax-checks '((sender . disabled)) message-default-headers (concat "X-Attribution: jao\n" "X-Clacks-Overhead: GNU Terry Pratchett\n" "X-URL: \n") message-hidden-headers '("^References:" "^Face:" "^X-Face:" "^X-Draft-From:") message-make-forward-subject-function 'message-forward-subject-fwd) (setq message-expand-name-standard-ui t) ;;;; adjust bcc (defvar jao-message--bcc-alist `((,(regexp-quote "mail@jao.io") . "proton@jao.io") (,(regexp-quote "jao@gnu.org") . "hacking@jao.io"))) (defun jao-message-insert-bcc () (when jao-notmuch-enabled (let ((f (or (message-fetch-field "From") ""))) (when-let (b (seq-some (lambda (x) (when (string-match-p (car x) f) (cdr x))) jao-message--bcc-alist)) (insert "Bcc: " b "\n"))))) ;; (when jao-notmuch-enabled ;; (add-hook 'message-header-setup-hook #'jao-message-insert-bcc)) ;;;; to->from (defvar jao-message-to-from nil) (defun jao-message-adjust-from () (let ((to (concat (message-fetch-field "To") (message-fetch-field "Cc")))) (when-let* ((tf (seq-find (lambda (tf) (string-match-p (car tf) to)) jao-message-to-from)) (from (message-make-from "Jose A Ortega Ruiz" (cdr tf)))) (save-restriction (widen) (message-replace-header "From" from))))) (when jao-notmuch-enabled (add-hook 'message-header-setup-hook #'jao-message-adjust-from)) ;;;; encryption (setq gnutls-min-prime-bits nil) (setq gnus-buttonized-mime-types '("multipart/encrypted" "multipart/signed" "multipart/alternative")) (setq mm-verify-option 'always) (setq mm-decrypt-option 'always) (setq mm-sign-option 'guided) (setq mm-encrypt-option 'guided) (setq mml-secure-passphrase-cache-expiry (* 3600 24) password-cache-expiry (* 3600 24)) (setq smime-CA-directory "/etc/ssl/certs/" smime-certificate-directory (expand-file-name "certs/" gnus-directory)) (with-eval-after-load "mm-decode" ;; Tells Gnus to inline the part (add-to-list 'mm-inlined-types "application/pgp$") ;; Tells Gnus how to display the part when it is requested (add-to-list 'mm-inline-media-tests '("application/pgp$" mm-inline-text identity)) ;; Tell Gnus not to wait for a request, just display the thing ;; straight away. (add-to-list 'mm-automatic-display "application/pgp$") ;; But don't display the signatures, please. (setq mm-automatic-display (remove "application/pgp-signature" mm-automatic-display))) ;; decide whether to encrypt or just sign outgoing messages (defvar jao-message-try-sign nil) (defun jao-message-maybe-sign () (when (and jao-message-try-sign (y-or-n-p "Sign message? ")) (if (y-or-n-p "Encrypt message? ") (let ((recipient (message-fetch-field "To"))) (if (or (pgg-lookup-key recipient) (and (y-or-n-p (format "Fetch %s's key? " recipient)) (pgg-fetch-key pgg-default-keyserver-address recipient))) (mml-secure-message-encrypt-pgp) (mml-secure-message-sign-pgp))) (mml-secure-message-sign-pgp)))) ;; for ma gnus (eval-after-load "rfc2047" '(add-to-list 'rfc2047-header-encoding-alist '("User-Agent" . address-mime))) ;;;; check attachment (defvar jao-message-attachment-regexp "\\([Ww]e send\\|[Ii] send\\|attach\\)") (defun jao-message-check-attachment () "Check if there is an attachment in the message if I claim it." (save-excursion (message-goto-body) (when (search-forward-regexp jao-message-attachment-regexp nil t nil) (message-goto-body) (unless (or (search-forward "<#part" nil t nil) (message-y-or-n-p "No attachment. Send the message? " nil nil)) (error "No message sent"))))) ;;;; check fcc/gcc (defun jao-message-check-gcc () "Ask whether to keep a copy of message." (save-excursion (save-restriction (message-narrow-to-headers) (when (and (or (message-fetch-field "Gcc") (message-fetch-field "Fcc")) (not (y-or-n-p "Archive? "))) (message-remove-header "\\(?:[BFG]cc\\)"))))) ;;;; check recipient (defun jao-message-check-recipient () (save-excursion (save-restriction (message-narrow-to-headers) (when-let ((to (message-fetch-field "To"))) (when (string-match-p jao-mails-regexp to) (unless (y-or-n-p "Message is addressed to yourself. Continue?") (error "Message not sent"))))))) ;;;; randomsig (with-eval-after-load "message" (when (require 'randomsig nil t) (define-key message-mode-map (kbd "C-c s") 'randomsig-replace-sig) (define-key message-mode-map (kbd "C-c S") 'randomsig-select-sig) (setq randomsig-dir (expand-file-name "~/etc/config/emacs")) (setq randomsig-files '("signatures.txt")) ;; or (setq randomsig-files (randomsig-search-sigfiles)) ;; or (setq randomsig-files 'randomsig-search-sigfiles) (setq message-signature 'randomsig-signature) (setq randomsig-delimiter-pattern "^%$" randomsig-delimiter "%"))) ;;;; send mail hooks (dolist (h '(jao-message-check-gcc jao-message-check-recipient jao-message-maybe-sign)) (add-hook 'message-send-hook h)) (unless jao-notmuch-enabled (add-hook 'message-send-hook #'jao-message-check-attachment)) ;;;; keybindings (with-eval-after-load "message" ;; (define-key message-mode-map [f7] 'mml-secure-message-sign-pgp) (define-key message-mode-map [f8] 'mml-secure-message-encrypt-pgp) (define-key message-mode-map (kbd "C-c y") #'yank-media)) ;;; sendmail/smtp (defun jao-sendmail-gmail () (setq smtpmail-auth-supported '(login cram-md5 plain)) (setq smtpmail-smtp-server "smtp.gmail.com") (setq smtpmail-smtp-service 587)) (defun jao-sendmail-local () (setq send-mail-function 'sendmail-send-it) (setq smtpmail-auth-supported nil) ;; (cram-md5 plain login) (setq smtpmail-servers-requiring-authorization nil) (setq smtpmail-smtp-user nil) (setq smtpmail-smtp-server "127.0.0.1") (setq smtpmail-smtp-service 25)) (defun jao-sendmail-msmtp () (setq send-mail-function 'sendmail-send-it sendmail-program "/usr/bin/msmtp" mail-specify-envelope-from t message-sendmail-envelope-from 'header mail-envelope-from 'header)) (jao-sendmail-local) ;;; bbdb ;; (jao-load-path "bbdb/lisp") (use-package bbdb :ensure t :init (setq bbdb-complete-name-allow-cycling t bbdb-completion-display-record nil bbdb-gui t bbdb-message-all-addresses t bbdb-complete-mail-allow-cycling t bbdb-north-american-phone-numbers-p nil bbdb-add-aka t bbdb-add-name 2 bbdb-message-all-addresses t bbdb-mua-pop-up t ;; 'horiz bbdb-mua-pop-up-window-size 0.3 bbdb-layout 'multi-line bbdb-mua-update-interactive-p '(query . create) bbdb-mua-auto-update-p 'bbdb-select-message bbdb-user-mail-address-re jao-mails-regexp bbdb-auto-notes-ignore-headers `(("From" . ,jao-mails-regexp) ("From" . ".*@.*github\.com.*") ("To" . ".*@.*github\.com.*") ("Reply-to" . ".*") ("References" . ".*")) bbdb-auto-notes-ignore-messages `(("To" . ".*@.*github\\.com.*") ("From" . ".*@.*github\\.com.*") ("From" . "info-list") ("From" . "no-?reply\\|deploy") ("X-Mailer" . "MailChimp")) bbdb-accept-message-alist `(("To" . ,jao-mails-regexp) ("Cc" . ,jao-mails-regexp) ("BCc" . ,jao-mails-regexp)) bbdb-ignore-message-alist bbdb-auto-notes-ignore-messages) :config (add-hook 'message-setup-hook 'bbdb-mail-aliases) ;; (add-hook 'bbdb-notice-mail-hook 'bbdb-auto-notes) (add-hook 'bbdb-after-change-hook (lambda (arg) (bbdb-save))) (require 'bbdb-anniv) ;; BBDB 3.x this gets birthdays in org agenda and diary (add-hook 'diary-list-entries-hook 'bbdb-anniv-diary-entries) (setq bbdb-file (expand-file-name "~/.emacs.d/bbdb")) (if jao-notmuch-enabled (bbdb-initialize 'message 'notmuch) (bbdb-initialize 'message 'pgp 'gnus))) ;; (load "bbdb-loaddefs") ;;; narrowing (defvar jao-mail-consult-buffer-history nil) (defun jao-mail-buffer-p (b) (or (member (buffer-name b) '("*Calendar*" "inbox.org" "*Org Agenda*" "*Fancy Diary Entries*" "diary")) (with-current-buffer b (derived-mode-p 'notmuch-show-mode 'notmuch-search-mode 'notmuch-tree-mode 'notmuch-hello-mode 'notmuch-message-mode 'gnus-group-mode 'gnus-summary-mode 'gnus-article-mode 'message-mode)))) (defvar jao-mail-consult-source (list :name "mail buffer" :category 'buffer :hidden t :narrow (cons ?n "mail buffer") :history 'jao-mail-consult-buffer-history :action (lambda (b) (when (not (string-blank-p (or b ""))) (jao-afio-goto-mail) (if (get-buffer-window b) (pop-to-buffer b) (pop-to-buffer-same-window b)))) :items (lambda () (mapcar #'buffer-name (seq-filter #'jao-mail-buffer-p (buffer-list)))))) (jao-consult-add-buffer-source 'jao-mail-consult-source) (require 'jao-custom-notmuch) ;;; . (provide 'jao-custom-email)