Search code examples
cssnode.jsemailejsnodemailer

How to import styles from css files into an .ejs template and send it over email?


What i want to do:

  1. Send one email with styles;
  2. Have separate files, one for my .ejs template and one .css for styles that correspond to that template.

What the problem is:

  1. If i create separate routes for the styles and insert it into the HTML, the user will need to "authorize" the download of these styles;
  2. If i just import like normal HTML, it will not go through the email.

What am i using:

  • Express.js
  • Typescript
  • EJS
  • nodemailer

What is my file structure like at the moment:

  • src
    • views
      1. index.ejs
      2. style.css
      • internal_view_group
        1. style.css
        • internal_template_name
          1. style.css
          • locale
            1. pt-br.ejs
            2. en-us.ejs
      • public_view_group
        1. style.css
        • public_template_name
          1. style.css
          • locale
            1. pt-br.ejs
            2. en-us.ejs

Ok, if the directory is a little messy or hard to understand, let me break it down for you:

  • Folder "views" contains all my templates and styles, it also contains my index.ejs, that's what i'll call for when rendering the HTML, this index will then call styles from the group, template and then call the HTML from template, considering the language it uses. It also has a style.css, a global stylesheet that must be used in all templates, regardless of it's group.

  • Folder "internal_view_group" is a group of templates, for example, we have an internal group, templates used for internal communication, and a public group, used for the general public communication. It also has a default style.css, that is applied to every template inside this group.

  • Folder "internal_template_name" is a template, it has it's locales inside "locales" folder and a stylesheet that must be applied onto the called locale.

How can i have this level of organization on my code, having separate files and still work, considering the section "The problem is"?


Solution

  • Since you use your index.ejs to call all other templates and styles, you can also directly inject the styles into this index.ejs using the <%- %> tag from EJS.

    What this tag does: import a file (usually an .EJS), read it's content and output it unscaped to the HTML.

    so what you want to do into the index.js is something similar to this:

    <head>
        <%-
            '<style>'
            + include(`./style.css`)
            + include(`./${template_group}/style.css`)
            + include(`./${template_group}/${template_name}/style.css`)
            + '</style>'
        %>
    </head>
    <body>
        <%- include(`./${template_group}/${template_name}/locale/${locale}.ejs`) %>
    </body>
    

    This will output all style RAW contents into the code (not a minified version).

    The reason for the style tag being surrounded by strings inside the javascript logic and not outside, surrounding the output, is that VSCode may report an error in your code because of EJS tags inside style sections, with this, nothing at output terminal will be reported.

    If you find that the final size of HTML code that you want to send is too large and may become a problem, you can use javascript prototype.String functions after the include, like include('./style.css').replaceAll(' ', ''), to replace all spaces but leave line breaks (not tested)