{"id":272,"date":"2016-07-22T02:11:44","date_gmt":"2016-07-22T00:11:44","guid":{"rendered":"http:\/\/lab.fawno.com\/?p=272"},"modified":"2022-03-07T13:39:56","modified_gmt":"2022-03-07T12:39:56","slug":"","status":"publish","type":"post","link":"https:\/\/lab.fawno.org.es\/en\/2016\/07\/22\/fawnoemail-enviar-emails-desde-cakephp-con-imagenes-embebidas\/","title":{"rendered":"","raw":""},"content":{"rendered":"","protected":false,"raw":""},"excerpt":{"rendered":"","protected":false,"raw":""},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_es_post_content":"<!-- wp:paragraph -->\n<p>Una de las ventajas de utilizar un <a href=\"https:\/\/es.wikipedia.org\/wiki\/Framework\" target=\"_blank\" rel=\"noopener noreferrer\">Framework<\/a> como <a href=\"https:\/\/cakephp.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">CakePHP<\/a> es que enviar emails es muy sencillo.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Sin embargo hay dos cosas que la clase CakeEmail no hace:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true} -->\n<ol><li>Detectar autom\u00e1ticamente los <a href=\"https:\/\/es.wikipedia.org\/wiki\/Multipurpose_Internet_Mail_Extensions\" target=\"_blank\" rel=\"noopener noreferrer\">tipos MIME<\/a><\/li><li>Embeber autom\u00e1ticamente las im\u00e1genes<\/li><\/ol>\n<!-- \/wp:list -->\n\n<!-- wp:paragraph -->\n<p>Para solucionar ambos puntos he creado una clase que extiende a CakeEmail dot\u00e1ndola de estas funcionalidades: <a href=\"https:\/\/github.com\/fawno\/FawnoEmail\" target=\"_blank\" rel=\"noopener noreferrer\">FawnoEmail<\/a>.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Para a\u00f1adir la detecci\u00f3n de los tipos MIME he clonado la funci\u00f3n <a href=\"https:\/\/api.cakephp.org\/2.8\/source-class-CakeEmail.html#1057\" target=\"_blank\" rel=\"noopener noreferrer\">attachments<\/a> de la clase original y le he a\u00f1adido el siguiente c\u00f3digo:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:enlighter\/codeblock {\"language\":\"php\",\"theme\":\"dracula\"} -->\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-theme=\"dracula\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">if (!isset($fileInfo['mimetype'])) {\n  if (function_exists('mime_content_type')) {\n    $fileInfo['mimetype'] = mime_content_type($fileInfo['file']);\n  } else {\n    $fileInfo['mimetype'] = 'application\/octet-stream';\n  }\n}<\/pre>\n<!-- \/wp:enlighter\/codeblock -->\n\n<!-- wp:paragraph -->\n<p>B\u00e1sicamente CakeEmail establece el MimeType como 'application\/octet-stream' para todos los adjuntos que no especifiquen expl\u00edcitamente un MimeType. Lo que he hecho es detectar si existe la funci\u00f3n \"<a href=\"https:\/\/php.net\/manual\/es\/function.mime-content-type.php\" target=\"_blank\" rel=\"noopener noreferrer\">mime_content_type<\/a>\" y usarla en caso afirmativo.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>En teor\u00eda la funci\u00f3n \"mime_content_type\" existe desde la versi\u00f3n 4.3 de PHP y por tanto no ser\u00eda necesario comprobar la existencia de la funci\u00f3n...<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Para embeber las im\u00e1genes de manera autom\u00e1tica he extendido la funci\u00f3n <a href=\"https:\/\/api.cakephp.org\/2.8\/source-class-CakeEmail.html#1661\" target=\"_blank\" rel=\"noopener noreferrer\">_renderTemplates<\/a>. En t\u00e9rminos sencillos el truco consiste en obtener el renderizado del mail antes de ser enviado, de esta forma buscamos las im\u00e1genes a embeber y procedemos a ello.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>La primera dificultad es determinar las im\u00e1genes que hay que embeber, lo he solucionado buscando todos las rutas que comiencen por \"file:\", \"file:\/\/\", \"cid:\" y \"cid:\/\/\".<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Para cada imagen genero un contentId que utilizo para adjuntar la imagen y luego como ruta en el cuerpo del mail:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:enlighter\/codeblock {\"language\":\"php\",\"theme\":\"dracula\"} -->\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"php\" data-enlighter-theme=\"dracula\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$rendered = parent::_renderTemplates($content);\n\nif (!empty($rendered['html'])) {\n  $rendered['html'] = str_replace(array('file:', 'file:\/\/', 'cid:\/\/'), 'cid:', $rendered['html']);\n  if (preg_match_all('~([\"\\'])cid:([^\\1]+)\\1~iU', $rendered['html'], $img)) {\n    $img = array_unique($img[2]);\n    foreach ($img as $file) if (is_file($file)) {\n      $cid = sha1($file);\n      $images['cid:' . $cid] = array('file' =&amp;gt; $file, 'contentId' =&amp;gt; $cid);\n      $files['cid:' . $cid] = $file;\n      $cids['cid:' . $cid] = $cid;\n    }\n    $this-&amp;gt;addAttachments($images);\n    $rendered['html'] = str_replace($files, $cids, $rendered['html']);\n  }\n}<\/pre>\n<!-- \/wp:enlighter\/codeblock -->\n\n<!-- wp:paragraph -->\n<p>En el <a href=\"https:\/\/github.com\/fawno\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub de Fawno<\/a> ten\u00e9is disponible la clase.<\/p>\n<!-- \/wp:paragraph -->","_es_post_name":"fawnoemail-enviar-emails-desde-cakephp-con-imagenes-embebidas","_es_post_excerpt":"","_es_post_title":"FawnoEmail: enviar emails desde CakePHP con im\u00e1genes embebidas","_en_post_content":"","_en_post_name":"","_en_post_excerpt":"","_en_post_title":"","edit_language":"en","footnotes":""},"categories":[15,5],"tags":[17,6],"class_list":["post-272","post","type-post","status-publish","format-standard","hentry","category-cakephp","category-php","tag-cakephp","tag-php"],"ninja_gutenberg_blocks_featured_media_urls":{"thumbnail":"","ninja_gutenberg_blocks_landscape_large":"","ninja_gutenberg_blocks_portrait_large":"","ninja_gutenberg_blocks_square_large":"","ninja_gutenberg_blocks_landscape":"","ninja_gutenberg_blocks_portrait":"","ninja_gutenberg_blocks_square":"","full":""},"_links":{"self":[{"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/posts\/272","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/comments?post=272"}],"version-history":[{"count":0,"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/posts\/272\/revisions"}],"wp:attachment":[{"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/media?parent=272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/categories?post=272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lab.fawno.org.es\/en\/wp-json\/wp\/v2\/tags?post=272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}