Reputation: 57
Is it possible to attach a file from the firebase storage?? I tried the following code but it doesn't work
var mailgun = require("mailgun-js");
var api_key = 'key-acf9f881e32c85b3c0dad34358507a95';
var DOMAIN = 'sandbox76c6f74ddab14862816390c16f37a272.mailgun.org';
var mailgun = require('mailgun-js')({apiKey: api_key, domain: DOMAIN});
var path = require("path");
var filepath = path.join(`gs://i-m-here-c01f6.appspot.com/Groups/${leaderId}`, 'group_image.jpg');
var data = {
from: 'Excited User <[email protected]>',
to: '[email protected]',
subject: 'Complex',
text: 'Group Creation Request',
html: `<p>A user named: ${fromName} wants to create a group.<br />
User ID: ${leaderId}<br />
Group Name: ${groupName}<br />
Group Description: ${groupDescription}<br /><br />
To Accept the request click here:<br />
https://us-central1-i-m-here-c01f6.cloudfunctions.net/acceptOrDenyGroupCreation?leaderID=${leaderId}&requestStatus=approved <br /><br />
To Deny the request click here:<br />
https://us-central1-i-m-here-c01f6.cloudfunctions.net/acceptOrDenyGroupCreation?leaderID=${leaderId}&requestStatus=denied /></p>`,
attachment: filepath
};
mailgun.messages().send(data, function (error, body) {
if(error)
console.log('email err: ',error);
});
please help
Upvotes: 2
Views: 5197
Reputation: 10522
[That's an example for Nodemailer, it took me so much time to attach dynamically an attachment from a Cloud Storage for Firebase. Therefore, hopefully it'll help out someone. You can find so many similarities.
All the examples are in Angular
/ TypeScript
.
It starts somewhere in the component.html file
<form
#formDirective="ngForm"
[formGroup]="contactForm"
(ngSubmit)="onSubmit(contactForm.value, formDirective)"
>
<mat-form-field>
<ngx-mat-file-input
(change)="uploadFile($event)"
formControlName="fileUploader"
multiple
type="file"
>
</ngx-mat-file-input>
</mat-form-field>
</form>
In component.ts
import { AngularFirestore } from '@angular/fire/firestore';
import {
AngularFireStorage,
AngularFireStorageReference,
AngularFireUploadTask,
} from '@angular/fire/storage';
import {
FormBuilder,
FormGroup,
FormGroupDirective,
Validators,
} from '@angular/forms';
import { throwError } from 'rxjs';
...
constructor(
private angularFirestore: AngularFirestore,
private angularFireStorage: AngularFireStorage,
private formBuilder: FormBuilder
) {}
public contentType: string[] = [];
public downloadURL: string[] = [];
public fileName: string = '';
public maxFileSize = 20971520;
public contactForm: FormGroup = this.formBuilder.group({
fileUploader: [
'',
Validators.compose([
// Your validators rules...
]),
],
...
});
...
public onSubmit(form: any, formDirective: FormGroupDirective): void {
form.contentType = this.contentType;
form.fileUploader = this.downloadURL;
form.fileName = this.fileName;
this.angularFirestore
.collection(String(process.env.FIRESTORE_COLLECTION_MESSAGES)) // Make sure the environmental variable is a string.
.add(form)
.then(() => {
// Your logic, such as alert...
.catch(() => {
// Your error handling logic...
});
}
public uploadFile(event: any): void {
// Iterate through all uploaded files.
for (let i = 0; i < event.target.files.length; i++) {
const file = event.target.files[i]; // Get each uploaded file.
const fileName = file.name + '_' + Date.now(); // It makes sure files with the same name will be uploaded more than once and each of them will have unique ID, showing date (in milliseconds) of the upload.
this.contentType = file.type;
this.fileName = fileName;
// Get file reference.
const fileRef: AngularFireStorageReference = this.angularFireStorage.ref(
fileName
);
// Create upload task.
const task: AngularFireUploadTask = this.angularFireStorage.upload(
fileName,
file,
file.type
);
// Upload file to Cloud Firestore.
task
.snapshotChanges()
.pipe(
finalize(() => {
fileRef.getDownloadURL().subscribe((downloadURL: string) => {
this.angularFirestore
.collection(String(process.env.FIRESTORE_COLLECTION_FILES)) // Make sure the environmental variable is a string.
.add({ downloadURL: downloadURL });
this.downloadURL.push(downloadURL);
});
}),
catchError((error: any) => {
return throwError(error);
})
)
.subscribe();
}
}
That's all frontend, now it's finally time for our backend.
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore';
import { EventContext } from 'firebase-functions';
async function onCreateSendEmail(
snap: DocumentSnapshot,
_context: EventContext
) {
try {
const contactFormData = snap.data();
// You can use those to debug your code...
console.log('Submitted contact form: ', contactFormData);
console.log('context: ', _context); // This log will be shown in Firebase Functions logs.
const mailTransport: Mail = nodemailer.createTransport({
// Make sure the environmental variables have proper typings.
host: String(process.env.MAIL_HOST),
port: Number(process.env.MAIL_PORT),
auth: {
user: String(process.env.MAIL_ACCOUNT),
pass: String(process.env.MAIL_PASSWORD),
},
tls: {
rejectUnauthorized: false, //! Fix ERROR "Hostname/IP doesn't match certificate's altnames".
},
});
const mailOptions = {
attachments: [
{
contentType: `${contactFormData!.contentType}`,
filename: `${contactFormData!.fileName}`,
path: `${contactFormData!.fileUploader}`,
},
],
... // Your other mails options such as bcc, from, to, subject, html...
};
await mailTransport.sendMail(mailOptions);
} catch (err) {
console.error(err);
}
}
That's more or less all the headache from frontend to backend a developer has to go through to dynamically attach file to an email with correct contentType
, downloadURL
, and fileName
. I was missing a complete solution for the case across WWW, that's why the front-to-back answer.
Note: The frontend is handling multiple file uploads on the UI/Cloud Storage for Firebase side and all the files are uploaded to Firebase. However, only one dynamically added attachment is working fine. I still can't figure out how to handle multiple dynamic files uploads.
Upvotes: 0
Reputation: 357
In the example you've given you are using the gs:://bucket-name/path
to download the file from Cloud Storage and send it as an attachment. In order to do so, you would need to use the request dependency as per the docs:
https://github.com/bojand/mailgun-js#attachments
In this case, all you would have to do is:
// var path = require("path");
const request = require('request');
var filepath = request(`gs://i-m-here-c01f6.appspot.com/Groups/${leaderId}`);
If you wanted to get more specific about assigning properties to the file, you can use the new mailgun.Attachments(options)
to pass in an options
parameter that looks something like this:
options: {
data: filepath,
filename: 'name,jpg',
contentType: 'image/jpeg',
knownLength: 2019121,
};
Where
Upvotes: 0
Reputation: 136
You can get it as a buffer and send it like this :
var request = require('request');
var file = request("https://www.google.ca/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png");
var data = {
from: 'Excited User <[email protected]>',
to: '[email protected]',
subject: 'Hello',
text: 'Testing some Mailgun awesomeness!',
attachment: file
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});
from here
Upvotes: 2
Reputation: 317477
You can't use a gs://bucket-name/path-to-file
URL to download a file from Cloud Storage just like it was an HTTP URL. Instead, you'll have to do one of these:
Upvotes: 4