I know this thread is a bit old, but I am still getting requests to investigate this on a number of my associates sites so I hope it helps other people who are desperate for clues.
There are in fact several mechanisms that can cause the symptom to appear, but because most of the ‘diagnostic’ information you need is hidden it takes several steps to identify the root cause. However, understanding what to look for is half the battle!
1 Javascript conflicts – well reported before and often indicated by errors appearing in the Javascript console on page load – usually conflicting versions are being loaded (most of the advice for this is readily available)
2 Unwanted HTML appearing in the AJAX results pages… you do not see this as it happens on the server behind the scenes, but the Javascript expects only certain responses to decide whether to put message sent ok or fail, and to hide the spinning wheel. If any unexpected characters appear in the response the Javascript silently fails and leaves the spinning wheel and usually no visible error message. However in this case the email is usually sent successfully even though web visitor does not see this.
The rogue characters could be anything output by a plugin, something in a theme/template or a PHP error/warning message! In my most recent case it was that Really Simple Captcha tried to delete the old images in the uploads folder on a Windows server, but due to a bug on that platform that has not been fixed it cannot unlink the image files until the ‘windows’ readonly attribute has been removed using this approach
unlink($file);
chmod($file, 0777);
This bug and fix has been documented elsewhere, but since the PHP warning appears on the AJAX call the user does not see the message generated as the Javascript discards it and places a standard AJAX error message onto the page into an ‘ajax-error’ span block saying ‘Unexpected Token <‘. Most style sheets are set to make this block not display, so you need to either modify the stylesheet or use Inspect Element to reveal the message.
The key thing is verifying whether your message is being sent, since the likely cause here may be some unexpected text and this may mean temporarily adding some diagnostic logging to disk in order to see what is happening at the various stages and I suggest you start by looking at the wpcf7_ajax_json_echo function inside controller.php located in the includes folder of the Contact Form 7 plugin. If this is your problem you will see the root cause as part of the function status parameters.