2
\$\begingroup\$

I have below code, which is basically handling inbound emails in my application, save the actual email content (text + attachments) to my database, and further save the actual attachment file on my server.

In my Email.php model, I have below function that handles the incoming email. The $token is the first string of the email. For example, my To: email can look like this: avdksokiell@myapp.com where avdksokiell is my token.

So as you can see, I fire off the Email model as below:

Mailbox::to('{token}@myapp.com', Email::class);

When above condition is met, below will be run:

public function __invoke(InboundEmail $email, $token)
{
    //Get the correct stream.
    $stream = Stream::where('token', $token)->firstOrFail();

    //Persist the token to the database. {token}@in.myapp.com
    $email->stream_id = $stream->id;

    //Save the email.
    $email->save();

    //If any attachments, persist them to the database.
    $this->storeAttachments($stream, $email);

}

Above works, because I have a relationship set up between Stream and Email:

Stream.php:

/**
 * A stream can have many e-mails
 */
public function emails()
{
    return $this->hasMany(Email::class);
}

Email.php:

/**
 * An email belongs to a Stream.
 */
public function stream()
{
    return $this->belongsTo(Stream::class);
}

Furthermore, in order to save the actual attachment from the mail, I have created a method called storeAttachments(Stream $stream, InboundEmail $email) function in Email that looks like below:

/**
 * A method to store incoming attachments from email.
 *
 */
public function storeAttachments(Stream $stream, InboundEmail $email)
{
    $attributes = [];
    foreach ($email->attachments() as $attachment) {
        //Set an unique filename
        $filename = uniqid() . '.' . File::extension($attachment->getFilename());
        //Store the file on the server
        $store = Storage::put($stream->token . '/' . $filename, $attachment->getContent());
        //Add file information, so we can persist it to the database.
        $attributes['name'] = $attachment->getFilename();
        $attributes['path'] = $stream->token . '/' . $filename;

        //Persist it to the database.
        $stream->addDocuments($attributes);
    }
}

Because my users can choose to:

  1. Upload files from a web frontend
  2. Send files by email into my app

I also have a Document model, that stores all the files:

I also have a relationship set up here:

Stream.php:

/**
 * A stream can have many documents
 */
public function documents()
{
    return $this->hasMany(Document::class);
}

Document.php:

//A document belongs to a Stream.
public function stream()
{
    return $this->belongsTo(Stream::class);
}

Now, for handling the saving files to the database, I have below method in my Stream model:

/**
 * Add document(s) to the stream
 *
 * @return Illuminate\Database\Eloquent\Model
 */
public function addDocuments(array $attributes)
{
    return $this->documents()->create($attributes);
}

I am a bit unsure if above design/methodology is correct and seen as "best practice".

One thing I notice is, that whenever I handle an incoming mail in the __invoke function, I run a query to get the stream_id by looking up the token, because the relationships is using stream_id.

Hope someone can help me shed some light if above is OK or if anything can be improved.

I'll be happy to share more code if needed.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.