Smart operator looks promising, but I have not tried it so I can't speak for it.
A prebuilt solution would be ideal, but if none are sufficient, it would be very easy to wrap write this functionality and wrap it in a minor mode though.
Here's my go:
(defvar auto-punc-punctuation-members
(string-to-list ".,:;?!")
"List of charactesr to insert spaces after")
(defvar auto-punc-ignore-members
(string-to-list " \t")
"List of characters to not auto insert spaces before")
(defun auto-punc-maybe-do ()
"If the last entered character is not in `auto-punc-punctuation-members' or `auto-punc-ignore-members',
and the prior character is in `auto-punc-punctuation-members',
insert a space between the two characters. "
(when (and auto-space-punctuation-mode
(not (member (char-before) (append auto-punc-punctuation-members auto-punc-ignore-members)))
(member (char-before (1- (point))) auto-punc-punctuation-members))
(backward-char 1)
(insert " ")
(forward-char 1)))
(define-minor-mode auto-space-punctuation-mode
"Automatically inserts spaces between some punctuation and other characters."
:init-value nil
:lighter "._a"
:keymap nil
(make-variable-buffer-local 'post-self-insert-hook)
(if auto-space-punctuation-mode
(add-hook 'post-self-insert-hook 'auto-punc-maybe-do)
(remove-hook 'post-self-insert-hook 'auto-punc-maybe-do)))
You could simply add it to your init and auto enable it when you want like
(add-hook 'text-mode-hook 'auto-space-punctuation-mode)
Everytime you insert a character the function auto-punc-maybe-do
runs, read the docstring to ensure this is the behavior you want. Basically if you type punctuation, then anything that is not punctuation or whitespace, a space will be inserted automatically.