See What is the motivation behind the introduction of preflight CORS requests?.
The reason CORS doesn’t require browsers to do a preflight for
text/plain content types is that if it did, that’d make CORS more restrictive than what browsers have already always allowed (and it’s not the intent of CORS to put new restrictions on what was already possible without CORS).
That is, with CORS, POST requests that you could do previously cross-origin are not preflighted—because browsers already allowed them before CORS existed, and servers knew about them. So CORS changes nothing about those “old” types of requests.
But prior to CORS, browsers wouldn’t allow you to do a cross-origin
application/json POST at all, and so servers could assume they wouldn’t receive them. That’s why a CORS preflight is required for those types of “new” requests and not for the “old” ones—to give a heads-up to the server: this is a different “new” type of request that they must explicitly opt-in to supporting.