You're not alone! :)
First, it is a very good point, IMO, to consider event receivers (ER) instead of workflows (WF) for your solution. WF are a heavy infrastructure, are complicated to use for end-users, do not migrate well, etc.
On the opposite, ER are transparent to end-users, you control excatly what happens, they work the same on 1 or 1000 items, you can easily update the code (if you have C# skills).
That being said, back to your problem:
First, a note about tasks
First thing to note is: you don't have to use/create tasks. The task concept in SharePoint is brought by WF, as a mean of communication between computers and humans. Its' always central when you cerate WF, but if you think about it, its confusing for end-users: when they want to approve a document, the document is cental, not the task!
The task is an artifact users don't care about: what they really want is to approve the document, not a random task. Do the test, and you'll see most users understand immediately the concept of approving a document, while approving a task to approve a document is a confusing mental double-hop. Not to mention the default task UI, that does nothing to help users mentally linking it to the document (no link to the doc, "OK" buttons instead of "Approve" buttons...).
So, what to do?
IMO, the best approach is to store the state of the document with the document. I mean adding a field on the document Library, e.g. "Lifecycle status". That column shoudl be read-only (and can even be hidden, but most of the time, users are happy to see it so they create views based on it), and serves mainly technical purpose.
When a new document is created, the ER triggers, does some checks if needed and sends notification emails out. This email contains a link to a custom page of yours (most of the time, an applicative page, Inside th _layouts folder).
When that page is hit, you can do some checks (does user have permissions to approve the doc, based on some dynamic/business conditions), and then display a business UI that talks about what the user expects: approving or not the document. You can easily link to the doc as well.
If the user approves the doc, you can do whatever you want from the code-behind of the page.
This also easily allows you to create a multi-states WF, as long as the "Lifecycle Status" column holds the current state.
An approach without a custom approval page:
If you don't want to create a dedicated applicative page, you can set the column "Lifecycle Status" as read-write. Any user with write-permissions on the document will be able to change him/her-self the status to anything like "Approved". You ER is trigered when this happens, and there you can check if he/she was allowed to do that. If not allowed, you revert the change back. If allowed, you actually publish the document from the ER.