I have just fulfilled (is that a good term?) two user stories out of a new project backlog I have just built. These are user registration and password reset, both requiring mail. I need to implement a substitute mail component because my initial choice, and a normally reliable one, wasn't working. Because I was focused on delivering the user stories, not debugging the mail component, I swapped it out to deliver working code at sprint end. Do I now log a new support issue for the mailer, or 're-insert' these stories into the backlog? If I do the latter, am I not introducing too much tech detail into user stories?
If you implemented the user story to the standards defined in the definition of done, then those user stories are finished and shouldn't be put back in the product backlog.
In similar situations I have raised a new user story, but described the requirement for making a technical change in terms of its business benefit, rather than having something purely technical in the product backlog. How about:
"As a developer I want the product to use the company standard email component so that support and maintenance is simplified."
As a developer, you're an actor too and you may have requirements that the system behaves in a particular way when you use (support / change) it. It should always be possible to articulate these in terms of their business benefit and prioritise them with your product owner alongside the implementation of new functionality.
If the definition of done for the user story are fullfiled (fullfilled, what every you want to call done) then your user store is complete and you shouldn't be putting it back in the backlog.
However you've taken on technical debt to complete that and later you need to devote other time to fixing that. So it sounds to me that you need a type of task for internal work such as refactors.
So add a new issue into the backlog.
Technical Debt is just another Story
If a story is done that means it has passed QA and been accepted by the Product Owner.
Any work that might need to be done to "clean up" or "improve" the implementation is considered Technical Debt and should simply be a new Story.
That way it will be tracked and prioritized by the Product Owner just like everything else.
According to your question and additional comments to @Klee's answer I think the problem is little bit different.
You completed a story. It should mean you passed all definitions of done - otherwise the user story cannot be considered as completed. But if you completed the story and passed all definitions of done it should mean that your current solution is satisfying. Otherwise the customer / product owner must rise the reason why it is not satisfying (not you) and either reject your completion or define another user story extending this one with new definition of done which are not satisfied by your current solution.
Technical debt is raised only when your current solution doesn't satisfy some requirement or constraint. Is there any constraint you have violated by using a workaround? If yes you should not mark your user story as completed in the first place.
Is there any code duplication or another bad practice introduced by your workaround? Then you have created technical debt and you should solve it ASAP. You can either be fair to product owner and simply tell him that during next sprint you must spend same time to fixing your technical issues which will result in less planed user stories. Or if your relation with product owner is not very good simply plan less user stories because of "newly" discovered complexities in any of them and fix your technical debt.
If there is no code duplication or any real reason why your code should be improved simply don't touch it. By the real reason I mean no customer / product owner defined constraint (for example company policy, performance, predefined time for creating a new email template which cannot be achieved with your current solution, etc.). There is no technical debt in your code. What you are trying to do is called golden plating - delivering features which were not required = wasting customers resources.
If your solution will not satisfy any future user story simply move your refactoring and code improving to that user story. It doesn't have to be solved now because it passed current definition of done. Deal with improvements when they have to be done to pass definition of done for newly implemented stories and to avoid bad practices.
The Simplest Thing That Will Reasonably Work
In a related comment, the OP says:
If that's the case, the original question is moot. The YAGNI principle requires that a solution not be over-engineered in anticipation of future requirements.
If a solution meets the current sprint goals, functions as designed, and meets the team's "definition of done," then it is done. It's not half-done, sort of done, or "done pending a planned refactoring."
Mark it done and move on.
If you genuinely think there's another story there, or some sort of technical debt that doesn't prevent the original story from being done, then you should raise another story for the Product Backlog.
New work always needs to be placed on the Product Backlog to raise visibility--no invisible work, ever! Ultimately, it is the Product Owner's job to decide whether the proposed improvement aligns with the product goals, and to prioritize your new user story within the Product Backlog if he chooses to add the story.