I have a c# project sending firebase messages via http post to clients having ios and android.
When clients uninstall my app their firebase device IDs are not deleted from my database unfortunately.
The next time I send a message to the device id witch corresponds to an user who uninstalled my app, of course the message is not delivered.
Is there any way to know if the message was not delivered ?
Unfortunately the response is always successful even if the message is not delivered.
My current code:
var firebaseMessage = new FirebaseMessage();
firebaseMessage.data = notificationMessages;
firebaseMessage.to = device.DeviceRegistrationId; <-- maybe this device is no longer valid
firebaseMessage.priority = "high";
firebaseMessage.notification = new ExpandoObject();
firebaseMessage.notification.title = "myApp";
firebaseMessage.notification.body = "testMessage";
firebaseMessage.notification.sound = "default";
firebaseMessage.notification.click_action = "FCM_PLUGIN_ACTIVITY";
firebaseMessage.notification.icon = "fcm_push_icon";
firebaseMessage.notification.delivery_receipt_requested= true;
var client = new HttpClient();
var appKey = "key=" + ApplicationConfig.FirebasKey;
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", appKey);
var response = await client.PostAsJsonAsync("https://fcm.googleapis.com/fcm/send", message);
return response;
When your app is uninstalled from a device, the corresponding registration token would then be invalidated by the FCM server, so any messages sent to that specific token would result to a NotRegistered response (also see my post here). In that event, you could proceed with deleting the token (or archiving it).
If your use-case intentionally wants to know if the message was received on the client side, you're gonna have to implement Delivery receipts.
Related
I'm trying to receive watch notification for Gmail mailboxes in my .NET C# program.
I have the following code:
WatchRequest body = new WatchRequest()
{
LabelIds = labelIds,
TopicName = PrivateKeys.GoogleGmailTopic
};
WatchResponse response = new UsersResource.WatchRequest(_gmailService, body, "me")
{
Key = PrivateKeys.GoogleApiKey,
OauthToken = AccessToken
}
.Execute();
... and it seems to work, since I get a response.
But where do I receive these notifications inside my program? How can I configure the event entry point?
Assuming you did the preliminary work to set up a Cloud Pub/Sub client (described here: https://developers.google.com/gmail/api/guides/push#initial_cloud_pubsub_setup), you should have a Pub/Sub subscription - either PULL or PUSH.
In order to get the notifications, your application should initiate a subscriber, you can follow the instructions in https://cloud.google.com/pubsub/docs/pull for PULL or in https://cloud.google.com/pubsub/docs/push for PUSH. Configuring the event entry point should be done as part of the subscriber set up.
I am trying to send a mail in Production with a verification link for a user registration.
For this, I have attached the credentials of the gmail account that sends the mail in my appsettings.json
APPSETTINGS.JSON:
The action of my controller that sends the mail is the following:
[HttpPost]
public async Task<JsonResult> Register(AddUserViewModel model)
{
if (ModelState.IsValid)
{
User user = await _userHelper.AddUserAsync(model, imageId);
if (user == null)
{
return Json("Email repeat");
}
string myToken = await _userHelper.GenerateEmailConfirmationTokenAsync(user);
string tokenLink = Url.Action("ConfirmEmail", "Account", new
{
userid = user.Id,
token = myToken
}, protocol: HttpContext.Request.Scheme);
Response response = _mailHelper.SendMail(model.Username, "App - ConfirmaciĆ³n de cuenta", $"<h1>App - ConfirmaciĆ³n de cuenta</h1>" +
$"Para habilitar el usuario, " +
$"por favor hacer clic en el siguiente enlace: </br></br>Confirmar Email");
if (response.IsSuccess)
{
return Json("Email send");
}
string message = response.Message;
return Json(message);
}
return Json("Model invalid");
}
The sendEmail method that returns a Response is as follows:
public Response SendMail(string to, string subject, string body)
{
try
{
string from = _configuration["Mail:From"];
string smtp = _configuration["Mail:Smtp"];
string port = _configuration["Mail:Port"];
string password = _configuration["Mail:Password"];
MimeMessage message = new MimeMessage();
message.From.Add(new MailboxAddress(from));
message.To.Add(new MailboxAddress(to));
message.Subject = subject;
BodyBuilder bodyBuilder = new BodyBuilder
{
HtmlBody = body
};
message.Body = bodyBuilder.ToMessageBody();
using (SmtpClient client = new SmtpClient())
{
client.CheckCertificateRevocation = false;
client.Connect(smtp, int.Parse(port), false);
client.Authenticate(from, password);
client.Send(message);
client.Disconnect(true);
}
return new Response { IsSuccess = true };
}
catch (Exception ex)
{
return new Response
{
IsSuccess = false,
Message = ex.Message,
Result = ex
};
}
}
The error message is the following:
"534: 5.7.14
\u003Chttps://accounts.google.com/signin/continue?sarp=1\u0026scc=1\u0026plt=AKgnsbt\n5.7.14
GCim6bqtaJeANyyQ0NvegYJS8qnYbDSCz3M0IMvB-rgIFdr1rLrIl1wbt4DkimTvNMLDl\n5.7.14
8dSGZxGuAWmDwX6gPD1T_lJ3U1e0G8EEAu6Lgt3p5gk1yJpr85Pm2mBN9nO4G33Y\u003E\n5.7.14
Please log in via your web browser and then try again.\n5.7.14 Learn
more at\n5.7.14 https://support.google.com/mail/answer/78754
t15sm12262168pjy.17 - gsmtp"
Am I sending correctly?
Should I change any gmail settings?
In the development environment the sending works without problems, any help or suggestion for me?
Directly using providers like Gmail, Outlook and similar ones is not advised because they perform checks that can disrupt your code just like you're seeing here.
This can happen without previous notice. And believe me, it will happen from time to time.
Common issues
Web-based OAuth flow
Most providers (Gmail specially) now enforce a web-based flow, from the most recent OAuth/OpenID specifications, for safer authentication/authorization.
This would be my first guess: Gmail auth (which is browser based) is simply blocking your login attempt because it wants you to use a browser and not simply submit your credentials.
There's a lot of background work done by IAM solutions to help protect users, namely called risk assessment. This, in time, might require both captcha and MFA challenges to be sent back to the user, so an API would not really work on this, that's another reason why they focus on browsers and not simply on getting the correct credentials.
Bot prevention
Email providers (specially Gmail) are great at detecting possible bots and this would be my second guess: it detected your service as a bot and put a temporary hold on your account to "protect you".
It's possible that this works on lower environments (aka: your machine and/or testing environment) and not production because of the server bot prevention system, which typically inspects IP address, user agent from the browser (if any), API call rate, authentication rate and others.
Usage rate limit
Yet another thing that can block you when doing such integration is the rate limit. Typically, 500 messages/month.
Possible solutions
Workaround - still using Gmail
To workaround this and still use Gmail, this is the way to go:
https://support.google.com/accounts/answer/185833?hl=en
It's called application password and is a different password that you generate on your account for a particular app to be allowed signing in. That will skip the OAuth and the bot validation (at least on most cases).
Proper long-term solution
The only reliable way to have this fixed is to use a proper send email service. Something like Amazon Simple Email Service, Sendgrid, or a bunch of others out there.
That's because they are created to be used by API calls and won't get in your way. You can set-up your own domain there, including SPF and DKIM keys so your recipient's email server will recognize the message as safe and indeed as coming from your (and not a random SPAM).
I want to get an email from my gmail sent items via c#.
I used this
service.Users.Messages.Get("me",id);
but it get 404 error.
All other apis works properly.
Thanks.
404 means that the Id you are requesting does not exist. I would run a List first then a get after.
If you want to see messages that are in the sent folder you should do a message.list
and search for what is in the sent folder.
var request = service.Users.Messages.List("me");
request.Q = "is:sent";
var result = request.Execute();
If you know when it was sent you could add a date.
var request = service.Users.Messages.List("me");
request.Q = "is:sent after:2021/3/28 before:2021/3/31";
var result = request.Execute();
Tip Q works just like the search function in the Gmail web application so if you can get that to return what you want just add it to Q
I raise a subscription request as below and the response is:
Subscription validation request failed. Must respond with 200 OK to this request.
Ho do I do I send this response please in UWP?
var result = await request.AddAsync(
new Subscription
{
ChangeType = "created,updated",
NotificationUrl = "https://webhook.azurewebsites.net/notificationClient",
Resource = "/me/mailfolders('inbox')/messages",
ExpirationDateTime = DateTimeOffset.Now.AddMinutes(20),
ClientState = Guid.NewGuid().ToString()
}
);
Ok, I think i need the webhook and the notificationClient, how/ where do i get these values?
Graph webhooks are not possible on UWP, at this time streaming notifications should be used from the outlook 365 api.
I am trying to build a continuous speech recognition from microphone using the Microsoft Cognitive Speech for Xamarin Android. I don't think there is library for Xamarin so I modified the "Xamarin.Cognitive.BingSpeech" library a little bit (the endpoint, etc) to get it work. I have some problem
I want to connect to the microsoft web socket by following tutorial from https://learn.microsoft.com/en-us/azure/cognitive-services/speech/api-reference-rest/websocketprotocol.
I tried sending HTTPREQUEST using basic HttpClient and got the 101 switch protocol result (I guess I succeed this part?).
UPDATE : My HTTP Request is :
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
var request = new HttpWebRequest(uriBuilder.Uri);
request.Headers.Add("Authorization", new System.Net.Http.Headers.AuthenticationHeaderValue(Bearer, AuthClient.Token).ToString());
request.Accept=MimeTypes.Json;
request.Host = SpeechEndpoint.Host;
request.Connection = "Upgrade";
request.Headers.Add("Upgrade", "Websocket");
request.KeepAlive = true;
request.Method = "GET";
request.CookieContainer = new CookieContainer();
request.AllowAutoRedirect = true;
request.Date = DateTime.Now;
request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.CacheIfAvailable);
request.Headers.Add("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
request.Headers.Add("Sec-WebSocket-Version", "13");
request.Headers.Add("Sec-WebSocket-Protocol", "chat, superchat");
request.Headers.Add("X-ConnectionId",xConnectionId = Guid.NewGuid().ToString().ToUpper());
After making a HTTPRequest, I am trying to connect to the websocket,
but I always get "Unable to connect to remote server" without any error code or anything. (wss://xxxxxxxx).
Uri wsuri = new Uri(AppConfig.BINGWSSURI);
await _socketclient.ConnectAsync(wsuri, CancellationToken.None);
Log.Info("WSOCKETFINISH", _socketclient.State.ToString());
The second thing I want to achieve is to stream the audio from microphone to the websocket using binary message, so I have to
Record from Microphone (I am using Plugin.AudioRecorder)
Cut it into small chunk pieces
Stream the small pieces asynchronously using the websocket
What I want to achieve : Speech to Text using Microphone with Microsoft Cognitive Speech, dictation mode, so I need partial result instead of waiting the recording to be completed.
I think you want to convert the speech to text. Since the Xamarin.Cognitive.BingSpeech needs you to record the speech and send them as file or stream to the server. I think you could try to use Android speech. And it could also convert text to speech. Here is an example.
If you want to use Xamarin.Cognitive.BingSpeech, you could use Audio Recorder plugin to record the speech and use BingSpeechApiClient to send to server. For example:
BingSpeechApiClient bingSpeechClient = new BingSpeechApiClient ("My Bing Speech API Subscription Key");
var audioFile = "/a/path/to/my/audio/file/in/WAV/format.wav";
var simpleResult = await bingSpeechClient.SpeechToTextSimple (audioFile);
Or
var simpleResult = await bingSpeechClient.SpeechToTextSimple (stream, <sample rate>, <audio record Task>);
Here is the example for Xamarin.Cognitive.BingSpeech.
Update:
I always get "Unable to connect to remote server" without any error code or anything.
You are missing something value in header.
X-ConnectionIdYou need to generate a UUID and add it to the header. For example: client.Options.SetRequestHeader("X-ConnectionId", System.Guid.NewGuid().ToString());
Authorization You need post your subscription key to https://api.cognitive.microsoft.com/sts/v1.0/issueToken. You could use Postman to do this. Then add the return value in the header.
client.Options.SetRequestHeader("Authorization", "eyJ0eXAiOiJKV1Q....uW72PAOBRcUvqY");
so I need partial result instead of waiting the recording to be completed
You could use the GetAudioFileStream() method.For example:
var audioRecordTask = await recorder.StartRecording();
using (var stream = recorder.GetAudioFileStream ())
{
//this will get the recording audio data as it continues to record
}
Update2:
The websoket part code:
var client = new ClientWebSocket();
client.Options.UseDefaultCredentials = true;
client.Options.SetRequestHeader("X-ConnectionId", System.Guid.NewGuid().ToString());
client.Options.SetRequestHeader("Authorization", "eyJ0eXAiOiJKV1QiL....16pbFPOWT3VHXot8");
var a = client.ConnectAsync(new Uri("wss://speech.platform.bing.com/speech/recognition/Dictation/cognitiveservices/v1"), CancellationToken.None);
a.Wait();
Note: Keep your Authorization's value up-to-date.