Symbol synchronization with M-QAM. M < 16
Are there any superior ways of doing symbol sync?


Yes! As you've noticed, your initial estimation of timing isn't "valid" forever.
This might be caused by clock jitter, or simply remaining sampling rate offset.

It's a very common problem in communication receivers.

What you can of course do is that you simply do the same estimate you did at the beginning periodically (with the already recovered data instead of a preamble, even!), or even simply for every symbol.

A popular way of doing so is basically using the derivative of the pulse shape to track the "flattest" point in the pulse-shaped receive signal even before applying the (typically matched) filter in the receive chain. You might want to watch this video (slides) of GNU Radio's synchronization expert Andy Walls – I like that talk especially since not only is it clear enough to be used as instructional material, it actually also addresses "how it is actually done".