How to render HTML into a variable programmatically
To render a plain node view, for example for emails, use this code:

$view_builder = \Drupal::entityTypeManager()-&gt;getViewBuilder('node');
$build = $view_builder-&gt;view($node, $view_mode, $langcode);
$html = \Drupal::service('renderer')-&gt;renderPlain($build);


If you want to customize the output, use a special view mode and a template node--[view-mode].html.twig.

Edit: Full page

You can build more complex render arrays:

  $view_builder = \Drupal::entityTypeManager()-&gt;getViewBuilder('node');
  $content = $view_builder-&gt;view($node, $view_mode, $langcode);
  $build = [
    '#type' =&gt; 'html',
    'page' =&gt; [
      '#type' =&gt; 'page',
      '#theme' =&gt; 'page',
      '#title' =&gt; 'Title',
      'content' =&gt; $content,
    ],
  ];

  $html = \Drupal::service('renderer')-&gt;renderPlain($build);


This is only a basic version of a page, if you want the full version with all features like attachments and libraries you need a request on Drupal.