2

I use mu4e to handle my 3 email accounts - Exchange, Posteo, Gmail. While I have no problem sending emails with Exchange and Posteo, I encounter the following issue when sending via Gmail:

Debugger entered--Lisp error: (error "Sending failed: 535-5.7.8 Username and Password not accepted. Learn more at\n535 5.7.8  https://support.google.com/mail/?p=BadCredentials c207sm5903330pfb.47 - gsmtp in response to AUTH")
  signal(error ("Sending failed: 535-5.7.8 Username and Password not accepted. Learn more at\n535 5.7.8  https://support.google.com/mail/?p=BadCredentials c207sm5903330pfb.47 - gsmtp in response to AUTH"))
  error("Sending failed: %s" "535-5.7.8 Username and Password not accepted. Learn more at\n535 5.7.8  https://support.google.com/mail/?p=BadCredentials c207sm5903330pfb.47 - gsmtp in response to AUTH")
  smtpmail-send-it()
  message-use-send-mail-function()
  message--default-send-mail-function()
  message-multi-smtp-send-mail()
  message--send-mail-maybe-partially()
  message-send-mail(nil)
  message-send-via-mail(nil)
  message-send(nil)
  message-send-and-exit()
  org-msg-ctrl-c-ctrl-c()
  run-hook-with-args-until-success(org-msg-ctrl-c-ctrl-c)
  (cond ((memq type '(src-block inline-src-block)) (if org-babel-no-eval-on-ctrl-c-ctrl-c nil (org-babel-eval-wipe-error-buffer) (org-babel-execute-src-block current-prefix-arg (org-babel-get-src-block-info nil context)))) ((org-match-line "[ \11]*$") (or (run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful...")))) ((memq type '(inline-babel-call babel-call)) (let ((info (org-babel-lob-get-info context))) (if info (progn (org-babel-execute-src-block nil info))))) ((eq type 'clock) (org-clock-update-time-maybe)) ((eq type 'dynamic-block) (save-excursion (goto-char (org-element-property :post-affiliated context)) (org-update-dblock))) ((eq type 'footnote-definition) (goto-char (org-element-property :post-affiliated context)) (call-interactively 'org-footnote-action)) ((eq type 'footnote-reference) (call-interactively #'org-footnote-action)) ((memq type '(inlinetask headline)) (save-excursion (goto-char (org-element-property :begin context)) (call-interactively #'org-set-tags-command))) ((eq type 'item) (let* ((box (org-element-property :checkbox context)) (struct (org-element-property :structure context)) (old-struct (copy-tree struct)) (parents (org-list-parents-alist struct)) (prevs (org-list-prevs-alist struct)) (orderedp (org-not-nil (org-entry-get nil "ORDERED")))) (org-list-set-checkbox (org-element-property :begin context) struct (cond ((equal arg ...) "[-]") ((and ... ...) "[ ]") ((or ... ...) nil) ((eq box ...) "[ ]") (t "[X]"))) (org-list-struct-fix-ind struct parents 2) (org-list-struct-fix-item-end struct) (org-list-struct-fix-bul struct prevs) (org-list-struct-fix-ind struct parents) (let ((block-item (org-list-struct-fix-box struct parents prevs orderedp))) (if (and box (equal struct old-struct)) (if (equal arg ...) (message "Checkboxes already reset") (user-error "Cannot toggle this checkbox: %s" ...)) (org-list-struct-apply-struct struct old-struct) (org-update-checkbox-count-maybe)) (if block-item (progn (message "Checkboxes were removed due to empty box at ..." ...)))))) ((eq type 'keyword) (let ((org-inhibit-startup-visibility-stuff t) (org-startup-align-all-tables nil)) (if (boundp 'org-table-coordinate-overlays) (progn (mapc #'delete-overlay org-table-coordinate-overlays) (setq org-table-coordinate-overlays nil))) (let* ((--invisible-types '...) (--markers\? 'use-markers) (--data (mapcar ... ...))) (unwind-protect (progn (org-mode-restart)) (save-excursion (save-restriction ... ... ...))))) (message "Local setup has been refreshed")) ((eq type 'plain-list) (let* ((begin (org-element-property :contents-begin context)) (struct (org-element-property :structure context)) (old-struct (copy-tree struct)) (first-box (save-excursion (goto-char begin) (looking-at org-list-full-item-re) (match-string-no-properties 3))) (new-box (cond (... "[-]") (... ...) (... "[ ]") (t "[X]")))) (cond (arg (let (...) (while --dolist-tail-- ...))) ((and first-box (eq ... begin)) (org-list-set-checkbox begin struct new-box))) (if (equal (org-list-write-struct struct (org-list-parents-alist struct) old-struct) old-struct) (progn (message "Cannot update this checkbox"))) (org-update-checkbox-count-maybe))) ((memq type '(node-property property-drawer)) (call-interactively #'org-property-action)) ((eq type 'radio-target) (call-interactively #'org-update-radio-target-regexp)) ((eq type 'statistics-cookie) (call-interactively #'org-update-statistics-cookies)) ((memq type '(table-row table-cell table)) (if (eq (org-element-property :type context) 'table\.el) (message "%s" (substitute-command-keys "\\<org-mode-map>Use `\\[org-edit-special]' to ...")) (if (or (eq type 'table) (and (eq type ...) (= ... ...))) (save-excursion (if (org-at-TBLFM-p) (progn ... ...) (goto-char ...) (org-call-with-arg ... ...) (orgtbl-send-table ...))) (org-table-maybe-eval-formula) (cond (arg (call-interactively ...)) ((org-table-maybe-recalculate-line)) (t (org-table-align)))))) ((eq type 'timestamp) (funcall pcase-0)) ((eq type 'planning) (cond ((org-at-timestamp-p 'lax) (funcall pcase-0)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) nil) (t (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful..."))))) ((null type) (cond ((org-at-heading-p) (call-interactively #'org-set-tags-command)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2)))) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2)))
  (let* ((pcase-2 #'(lambda nil (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here")))) (pcase-1 #'(lambda nil)) (pcase-0 #'(lambda nil (org-timestamp-change 0 'day)))) (cond ((memq type '(src-block inline-src-block)) (if org-babel-no-eval-on-ctrl-c-ctrl-c nil (org-babel-eval-wipe-error-buffer) (org-babel-execute-src-block current-prefix-arg (org-babel-get-src-block-info nil context)))) ((org-match-line "[ \11]*$") (or (run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here")))) ((memq type '(inline-babel-call babel-call)) (let ((info (org-babel-lob-get-info context))) (if info (progn (org-babel-execute-src-block nil info))))) ((eq type 'clock) (org-clock-update-time-maybe)) ((eq type 'dynamic-block) (save-excursion (goto-char (org-element-property :post-affiliated context)) (org-update-dblock))) ((eq type 'footnote-definition) (goto-char (org-element-property :post-affiliated context)) (call-interactively 'org-footnote-action)) ((eq type 'footnote-reference) (call-interactively #'org-footnote-action)) ((memq type '(inlinetask headline)) (save-excursion (goto-char (org-element-property :begin context)) (call-interactively #'org-set-tags-command))) ((eq type 'item) (let* ((box (org-element-property :checkbox context)) (struct (org-element-property :structure context)) (old-struct (copy-tree struct)) (parents (org-list-parents-alist struct)) (prevs (org-list-prevs-alist struct)) (orderedp (org-not-nil (org-entry-get nil "ORDERED")))) (org-list-set-checkbox (org-element-property :begin context) struct (cond ((equal arg ...) "[-]") ((and ... ...) "[ ]") ((or ... ...) nil) ((eq box ...) "[ ]") (t "[X]"))) (org-list-struct-fix-ind struct parents 2) (org-list-struct-fix-item-end struct) (org-list-struct-fix-bul struct prevs) (org-list-struct-fix-ind struct parents) (let ((block-item (org-list-struct-fix-box struct parents prevs orderedp))) (if (and box (equal struct old-struct)) (if (equal arg ...) (message "Checkboxes already reset") (user-error "Cannot toggle this checkbox: %s" ...)) (org-list-struct-apply-struct struct old-struct) (org-update-checkbox-count-maybe)) (if block-item (progn (message "Checkboxes were removed due to empty box at line %..." ...)))))) ((eq type 'keyword) (let ((org-inhibit-startup-visibility-stuff t) (org-startup-align-all-tables nil)) (if (boundp 'org-table-coordinate-overlays) (progn (mapc #'delete-overlay org-table-coordinate-overlays) (setq org-table-coordinate-overlays nil))) (let* ((--invisible-types '...) (--markers\? 'use-markers) (--data (mapcar ... ...))) (unwind-protect (progn (org-mode-restart)) (save-excursion (save-restriction ... ... ...))))) (message "Local setup has been refreshed")) ((eq type 'plain-list) (let* ((begin (org-element-property :contents-begin context)) (struct (org-element-property :structure context)) (old-struct (copy-tree struct)) (first-box (save-excursion (goto-char begin) (looking-at org-list-full-item-re) (match-string-no-properties 3))) (new-box (cond (... "[-]") (... ...) (... "[ ]") (t "[X]")))) (cond (arg (let (...) (while --dolist-tail-- ...))) ((and first-box (eq ... begin)) (org-list-set-checkbox begin struct new-box))) (if (equal (org-list-write-struct struct (org-list-parents-alist struct) old-struct) old-struct) (progn (message "Cannot update this checkbox"))) (org-update-checkbox-count-maybe))) ((memq type '(node-property property-drawer)) (call-interactively #'org-property-action)) ((eq type 'radio-target) (call-interactively #'org-update-radio-target-regexp)) ((eq type 'statistics-cookie) (call-interactively #'org-update-statistics-cookies)) ((memq type '(table-row table-cell table)) (if (eq (org-element-property :type context) 'table\.el) (message "%s" (substitute-command-keys "\\<org-mode-map>Use `\\[org-edit-special]' to edit t...")) (if (or (eq type 'table) (and (eq type ...) (= ... ...))) (save-excursion (if (org-at-TBLFM-p) (progn ... ...) (goto-char ...) (org-call-with-arg ... ...) (orgtbl-send-table ...))) (org-table-maybe-eval-formula) (cond (arg (call-interactively ...)) ((org-table-maybe-recalculate-line)) (t (org-table-align)))))) ((eq type 'timestamp) (funcall pcase-0)) ((eq type 'planning) (cond ((org-at-timestamp-p 'lax) (funcall pcase-0)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) nil) (t (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here"))))) ((null type) (cond ((org-at-heading-p) (call-interactively #'org-set-tags-command)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2)))) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2))))
  (let* ((context (org-element-lineage (org-element-context) '(babel-call clock dynamic-block footnote-definition footnote-reference inline-babel-call inline-src-block inlinetask item keyword node-property paragraph plain-list planning property-drawer radio-target src-block statistics-cookie table table-cell table-row timestamp) t)) (type (org-element-type context))) (if (eq type 'paragraph) (progn (let ((parent (org-element-property :parent context))) (if (and (eq (org-element-type parent) 'item) (= (line-beginning-position) (org-element-property :begin parent))) (progn (setq context parent) (setq type 'item)))))) (let* ((pcase-2 #'(lambda nil (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here")))) (pcase-1 #'(lambda nil)) (pcase-0 #'(lambda nil (org-timestamp-change 0 'day)))) (cond ((memq type '(src-block inline-src-block)) (if org-babel-no-eval-on-ctrl-c-ctrl-c nil (org-babel-eval-wipe-error-buffer) (org-babel-execute-src-block current-prefix-arg (org-babel-get-src-block-info nil context)))) ((org-match-line "[ \11]*$") (or (run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here")))) ((memq type '(inline-babel-call babel-call)) (let ((info (org-babel-lob-get-info context))) (if info (progn (org-babel-execute-src-block nil info))))) ((eq type 'clock) (org-clock-update-time-maybe)) ((eq type 'dynamic-block) (save-excursion (goto-char (org-element-property :post-affiliated context)) (org-update-dblock))) ((eq type 'footnote-definition) (goto-char (org-element-property :post-affiliated context)) (call-interactively 'org-footnote-action)) ((eq type 'footnote-reference) (call-interactively #'org-footnote-action)) ((memq type '(inlinetask headline)) (save-excursion (goto-char (org-element-property :begin context)) (call-interactively #'org-set-tags-command))) ((eq type 'item) (let* ((box (org-element-property :checkbox context)) (struct (org-element-property :structure context)) (old-struct (copy-tree struct)) (parents (org-list-parents-alist struct)) (prevs (org-list-prevs-alist struct)) (orderedp (org-not-nil ...))) (org-list-set-checkbox (org-element-property :begin context) struct (cond (... "[-]") (... "[ ]") (... nil) (... "[ ]") (t "[X]"))) (org-list-struct-fix-ind struct parents 2) (org-list-struct-fix-item-end struct) (org-list-struct-fix-bul struct prevs) (org-list-struct-fix-ind struct parents) (let ((block-item ...)) (if (and box ...) (if ... ... ...) (org-list-struct-apply-struct struct old-struct) (org-update-checkbox-count-maybe)) (if block-item (progn ...))))) ((eq type 'keyword) (let ((org-inhibit-startup-visibility-stuff t) (org-startup-align-all-tables nil)) (if (boundp 'org-table-coordinate-overlays) (progn (mapc ... org-table-coordinate-overlays) (setq org-table-coordinate-overlays nil))) (let* ((--invisible-types ...) (--markers\? ...) (--data ...)) (unwind-protect (progn ...) (save-excursion ...)))) (message "Local setup has been refreshed")) ((eq type 'plain-list) (let* ((begin (org-element-property :contents-begin context)) (struct (org-element-property :structure context)) (old-struct (copy-tree struct)) (first-box (save-excursion ... ... ...)) (new-box (cond ... ... ... ...))) (cond (arg (let ... ...)) ((and first-box ...) (org-list-set-checkbox begin struct new-box))) (if (equal (org-list-write-struct struct ... old-struct) old-struct) (progn (message "Cannot update this checkbox"))) (org-update-checkbox-count-maybe))) ((memq type '(node-property property-drawer)) (call-interactively #'org-property-action)) ((eq type 'radio-target) (call-interactively #'org-update-radio-target-regexp)) ((eq type 'statistics-cookie) (call-interactively #'org-update-statistics-cookies)) ((memq type '(table-row table-cell table)) (if (eq (org-element-property :type context) 'table\.el) (message "%s" (substitute-command-keys "\\<org-mode-map>Use `\\[org-edit-special]' to edit t...")) (if (or (eq type ...) (and ... ...)) (save-excursion (if ... ... ... ... ...)) (org-table-maybe-eval-formula) (cond (arg ...) (...) (t ...))))) ((eq type 'timestamp) (funcall pcase-0)) ((eq type 'planning) (cond ((org-at-timestamp-p 'lax) (funcall pcase-0)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) nil) (t (user-error (substitute-command-keys "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here"))))) ((null type) (cond ((org-at-heading-p) (call-interactively #'org-set-tags-command)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2)))) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2)))))
  (cond ((or (and (boundp 'org-clock-overlays) org-clock-overlays) org-occur-highlights) (if (boundp 'org-clock-overlays) (progn (org-clock-remove-overlays))) (org-remove-occur-highlights) (message "Temporary highlights/overlays removed from current...")) ((and (local-variable-p 'org-finish-function) (fboundp org-finish-function)) (funcall org-finish-function)) ((org-babel-hash-at-point)) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-hook)) (t (let* ((context (org-element-lineage (org-element-context) '(babel-call clock dynamic-block footnote-definition footnote-reference inline-babel-call inline-src-block inlinetask item keyword node-property paragraph plain-list planning property-drawer radio-target src-block statistics-cookie table table-cell table-row timestamp) t)) (type (org-element-type context))) (if (eq type 'paragraph) (progn (let ((parent ...)) (if (and ... ...) (progn ... ...))))) (let* ((pcase-2 #'(lambda nil ...)) (pcase-1 #'(lambda nil)) (pcase-0 #'(lambda nil ...))) (cond ((memq type '...) (if org-babel-no-eval-on-ctrl-c-ctrl-c nil (org-babel-eval-wipe-error-buffer) (org-babel-execute-src-block current-prefix-arg ...))) ((org-match-line "[ \11]*$") (or (run-hook-with-args-until-success ...) (user-error ...))) ((memq type '...) (let (...) (if info ...))) ((eq type 'clock) (org-clock-update-time-maybe)) ((eq type 'dynamic-block) (save-excursion (goto-char ...) (org-update-dblock))) ((eq type 'footnote-definition) (goto-char (org-element-property :post-affiliated context)) (call-interactively 'org-footnote-action)) ((eq type 'footnote-reference) (call-interactively #'org-footnote-action)) ((memq type '...) (save-excursion (goto-char ...) (call-interactively ...))) ((eq type 'item) (let* (... ... ... ... ... ...) (org-list-set-checkbox ... struct ...) (org-list-struct-fix-ind struct parents 2) (org-list-struct-fix-item-end struct) (org-list-struct-fix-bul struct prevs) (org-list-struct-fix-ind struct parents) (let ... ... ...))) ((eq type 'keyword) (let (... ...) (if ... ...) (let* ... ...)) (message "Local setup has been refreshed")) ((eq type 'plain-list) (let* (... ... ... ... ...) (cond ... ...) (if ... ...) (org-update-checkbox-count-maybe))) ((memq type '...) (call-interactively #'org-property-action)) ((eq type 'radio-target) (call-interactively #'org-update-radio-target-regexp)) ((eq type 'statistics-cookie) (call-interactively #'org-update-statistics-cookies)) ((memq type '...) (if (eq ... ...) (message "%s" ...) (if ... ... ... ...))) ((eq type 'timestamp) (funcall pcase-0)) ((eq type 'planning) (cond (... ...) (... nil) (t ...))) ((null type) (cond (... ...) (... ...) (t ...))) ((run-hook-with-args-until-success 'org-ctrl-c-ctrl-c-final-hook) (funcall pcase-1)) (t (funcall pcase-2)))))))
  org-ctrl-c-ctrl-c(nil)
  funcall-interactively(org-ctrl-c-ctrl-c nil)
  call-interactively(org-ctrl-c-ctrl-c nil nil)
  command-execute(org-ctrl-c-ctrl-c)

I use 2-factor authentication and hence I have created an app password for mu4e. My ~/.authinfo.gpg for Gmail looks as follows:

machine imap.gmail.com login kaletejas2006@gmail.com password <app password> port 993
machine smtp.gmail.com login kaletejas2006@gmail.com password <app password> port 587

My mu4e configuration relevant to Gmail is as follows:

(use-package mu4e
  :load-path "/usr/local/share/emacs/site-lisp/mu/mu4e"
  :config
  (setq mu4e-maildir "~/Maildir")
  ;; in my gmail account, any message marked for deletion will go to trash.
  (setq mu4e-contexts
        `( ,(make-mu4e-context
             :name "Gmail"
             :match-func (lambda (msg) (when msg
                                    (string-prefix-p "/Gmail" (mu4e-message-field msg :maildir))))
             :vars '(
                                        ;(mu4e-maildir . "~/maildir/gmail")
                     (mu4e-sent-folder . "/Gmail/[Gmail].Sent Mail")
                     (mu4e-drafts-folder . "/Gmail/[Gmail].Drafts")
                     (mu4e-trash-folder . "/Gmail/[Gmail].Trash")
                     (mu4e-refile-folder . "/Gmail/[Gmail].Archive")))
           ))

  ;; allow for updating mail using 'u' in the main view:
  (setq mu4e-get-mail-command "offlineimap")

  (require 'smtpmail)

  ;; now i set a list of
  (defvar my-mu4e-account-alist
    '(("Gmail"
       (mu4e-sent-folder "/Gmail/[Gmail].Sent Mail")
       (user-mail-address "kaletejas2006@gmail.com")
       (smtpmail-smtp-user "Tejas Kale")
       (smtpmail-local-domain "gmail.com")
       (smtpmail-default-smtp-server "smtp.gmail.com")
       (smtpmail-smtp-server "smtp.gmail.com")
       (smtpmail-smtp-service 587)
       )
      ))

  (defun my-mu4e-set-account ()
    "set the account for composing a message.
    this function is taken from:
        https://www.djcbsoftware.nl/code/mu/mu4e/multiple-accounts.html"
    (let* ((account
            (if mu4e-compose-parent-message
                (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir)))
                  (string-match "/\\(.*?\\)/" maildir)
                  (match-string 1 maildir))
              (completing-read (format "Compose with account: (%s) "
                                       (mapconcat #'(lambda (var) (car var))
                                                  my-mu4e-account-alist "/"))
                               (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist)
                               nil t nil nil (caar my-mu4e-account-alist))))
           (account-vars (cdr (assoc account my-mu4e-account-alist))))
      (if account-vars
          (mapc #'(lambda (var)
                    (set (car var) (cadr var)))
                account-vars)
        (error "No email account found"))))
  (add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account)

  ;; save attachments to downloads
  (setq mu4e-attachment-dir "/Users/tejas/Downloads/")

  ;; don't keep message buffers around.
  (setq message-kill-buffer-on-exit t)

  ;; use helm to select mailboxes.
  (setq mu4e-completing-read-function 'completing-read)

  ;; do not ask for context everytime mu4e is opened.
  (setq mu4e-context-policy 'pick-first)

  ;; do not ask when quitting.
  (setq mu4e-confirm-quit nil))

Any idea what I'm doing wrong? Thanks...

6
  • 1
    (setq smtpmail-debug-info t), retry, and look for a buffer whose name starts with '*trace of SMTP session'. That buffer will contain the actual SMTP commands that are being sent, it might indicate where the problem lies.
    – rpluim
    Mar 28, 2020 at 11:48
  • @rpluim Thanks for your response. I have pasted the trace here. Any idea what's wrong?
    – tejas_kale
    Mar 28, 2020 at 17:55
  • Hmm, maybe you need to specify your username in authinfo.gpg without the '@gmail.com' bit? That's what I have locally
    – rpluim
    Mar 29, 2020 at 13:55
  • That did not help. It gave the same error trace.
    – tejas_kale
    Mar 29, 2020 at 15:09
  • Hmm, (setq auth-source-debug t) will have auth-source log stuff to 'Messages', maybe the wrong thing is being looked up.
    – rpluim
    Mar 29, 2020 at 17:32

1 Answer 1

1

I had set the variable smtpmail-smtp-user to my name instead of my email ID. Correcting it got rid of the error. Thanks to @rpluim for helping me debug the issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.